home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’94 / [√] Distribution Restricted! / Christian Ruse / Fourier Paper + Apps / nih-image154_source.sea / V1.54 Source / Macros1.p < prev    next >
Text File  |  1994-02-01  |  103KB  |  4,760 lines

  1. unit Macros1;
  2. {Contains the recursive descent parser/interpreter}
  3. {for Image's Pascal-like macro language.}
  4.  
  5. {References:}
  6. {  "Pascal User Manual and Report", Kathleen Jensen and Niklaus Wirth, Springer-Verlag}
  7. {  "Building Your Own C Interpreter", Dr. Dobb's Journal, August 1989}
  8.  
  9. interface
  10.  
  11.     uses
  12.         QuickDraw, Palettes, Picker, PrintTraps, Globals, Utilities, Graphics, Edit, {}
  13.         Analysis, Camera, File1, File2, Filters, Macros2, Stacks, Lut, Background, {}
  14.         User, Serial, PlugIns, Text, projection, math; {,UMacroDef, UMacroRun}
  15.  
  16.  
  17.     procedure RunMacro (nMacro: integer);
  18.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  19.     procedure CloseSerialPorts;
  20.  
  21.  
  22. implementation
  23.  
  24.     const
  25.         EndExpected = '"end" or ";" expected';
  26.         ThenExpected = '"then" expected';
  27.         DivideByZero = 'Divide by zero';
  28.         DoExpected = '"do" expected';
  29.         UntilExpected = '"until" expected';
  30.         RightParenExpected = '")" expected';
  31.         NoImageOpen = 'No Image open';
  32.         MaxArgs = 25;
  33.  
  34.     var
  35.         nSaves, ErrorPC, LineStartPC: integer;
  36.         DoOption: boolean;
  37.         SaveBackground, SavePicWidth, SavePicHeight: integer;
  38.         SaveMethod: rsMethodType;
  39.         SaveCreate, SaveInvertY, SaveScaleArithmetic, SaveScaleConvolutions: boolean;
  40.         SaveAngle, SaveH, SaveV: real;
  41.         MacroOpPending, StringsAllocated, InPhotoMode: boolean;
  42.         RoutinesCalled: set of CommandType;
  43.  
  44.  
  45.  
  46.     function GetExpression: extended;
  47.     forward;
  48.     procedure DoStatement;
  49.     forward;
  50.     procedure SkipStatement;
  51.     forward;
  52.     procedure DoFor;
  53.     forward;
  54.     procedure MacroError (str: str255);
  55.     forward;
  56.     function GetString: str255;
  57.     forward;
  58.     function GetInteger: LongInt;
  59.     forward;
  60.     procedure SkipIf;
  61.     forward;
  62.     procedure SkipPartialStatement;
  63.     forward;
  64.  
  65.  
  66. {$S MacroUtil}
  67. {Routines from here to the $S compiler directive go in the MacroUtil segment}
  68.  
  69.  
  70.     procedure PutTokenBack;
  71.     begin
  72.         if token <> DoneT then begin
  73.                 pc := SavePC;
  74.                 token := SaveToken;
  75.             end;
  76.     end;
  77.  
  78.  
  79.     procedure DeallocateStrings (first, last: integer);
  80.         var
  81.             i: integer;
  82.     begin
  83.         with MacrosP^ do begin
  84.                 for i := first to last do begin
  85.                         if Stack[i].StringH <> nil then begin
  86.                                 DisposHandle(handle(Stack[i].StringH));
  87.                                 Stack[i].StringH := nil;
  88.                             end;
  89.                     end;
  90.             end;
  91.     end;
  92.  
  93.  
  94.     procedure TrimString (var str: str255);
  95.     begin
  96.         if length(str) > 0 then begin
  97.                 while (length(str) > 1) and (str[1] = ' ') do
  98.                     delete(str, 1, 1);
  99.                 while (length(str) > 1) and ((str[length(str)] = ' ') or (str[length(str)] = ';')) do
  100.                     delete(str, length(str), 1);
  101.             end;
  102.     end;
  103.  
  104.  
  105.     procedure LookupVariable;
  106.         var
  107.             VarFound: boolean;
  108.             i: integer;
  109.     begin
  110.         with MacrosP^ do begin
  111.                 VarFound := false;
  112.                 i := TopOfStack + 1;
  113.                 repeat
  114.                     i := i - 1;
  115.                     VarFound := SymbolTableLoc = Stack[i].SymbolTableIndex
  116.                 until VarFound or (i = 1);
  117.                 if VarFound then
  118.                     with stack[i] do begin
  119.                             TokenValue := value;
  120.                             if vType <> StringVar then
  121.                                 token := Variable
  122.                             else begin
  123.                                     token := StringVariable;
  124.                                     if StringH <> nil then
  125.                                         TokenStr := StringH^^
  126.                                     else
  127.                                         TokenStr := 'Deallocated String';
  128.                                 end;
  129.                             TokenStackLoc := i;
  130.                         end;
  131.             end; {with}
  132.     end;
  133.  
  134.  
  135.     function FetchInteger: integer;
  136.         var
  137.             temp: integer;
  138.     begin
  139.         with macrosP^ do begin
  140.                 temp := ord(macros[pc]);
  141.                 pc := pc + 1;
  142.                 FetchInteger := bor(bsl(temp, 8), ord(macros[pc]));
  143.                 pc := pc + 1;
  144.             end;
  145.     end;
  146.  
  147.  
  148.     procedure LookupProcedure;
  149.     begin
  150.         with MacrosP^ do begin
  151.                 SymbolTableLoc := FetchInteger;
  152.                 with SymbolTable[SymbolTableLoc] do begin
  153.                         TokenLoc := loc;
  154.                         TokenSymbol := symbol;
  155.                     end;
  156.             end;
  157.     end;
  158.  
  159.  
  160.     function FetchReal: real;
  161.         var
  162.             temp: LongInt;
  163.     begin
  164.         with macrosP^ do begin
  165.                 temp := ord(macros[pc]);
  166.                 pc := pc + 1;
  167.                 temp := bor(bsl(temp, 8), ord(macros[pc]));
  168.                 pc := pc + 1;
  169.                 temp := bor(bsl(temp, 8), ord(macros[pc]));
  170.                 pc := pc + 1;
  171.                 temp := bor(bsl(temp, 8), ord(macros[pc]));
  172.                 pc := pc + 1;
  173.                 FetchReal := real(temp);
  174.             end;
  175.     end;
  176.  
  177.  
  178.     procedure GetToken;
  179.     begin
  180.         with MacrosP^ do begin
  181.                 if token = DoneT then
  182.                     exit(GetToken);
  183.                 SavePC := PC;
  184.                 SaveToken := token;
  185.                 token := TokenType(macros[pc]);
  186.                 while token = NewLineT do begin
  187.                         MacroLineNumber := MacroLineNumber + 1;
  188.                         pc := pc + 1;
  189.                         LineStartPC := pc;
  190.                         if pc > EndMacros then begin
  191.                                 Token := DoneT;
  192.                                 exit(GetToken);
  193.                             end;
  194.                         SavePC := PC;
  195.                         SaveToken := token;
  196.                         token := TokenType(macros[pc]);
  197.                     end;
  198.                 pc := pc + 1;
  199.                 if pc > EndMacros then begin
  200.                         Token := DoneT;
  201.                         exit(GetToken);
  202.                     end;
  203.                 case token of
  204.                     CommandT, FunctionT, StringFunctionT, ArrayT, UserCommandT, UserFuncT, UserStrFuncT: 
  205.                         MacroCommand := CommandType(FetchInteger);
  206.                     Identifier:  begin
  207.                             SymbolTableLoc := FetchInteger;
  208.                             if TopOfStack > 0 then
  209.                                 LookupVariable;
  210.                         end;
  211.                     ProcedureT: 
  212.                         LookupProcedure;
  213.                     NumericLiteral: 
  214.                         TokenValue := FetchReal;
  215.                     StringLiteral:  begin
  216.                             TokenStr := '';
  217.                             while macros[pc] <> chr(0) do begin
  218.                                     TokenStr := concat(TokenStr, macros[pc]);
  219.                                     pc := pc + 1;
  220.                                 end;
  221.                             pc := pc + 1;
  222.                         end;
  223.                 end; {case}
  224.             end; {with}
  225.     end;
  226.  
  227.  
  228.     procedure GetMacroName;
  229.         var
  230.             i, len: integer;
  231.     begin
  232.         with MacrosP^ do begin
  233.                 pc := PCStart;
  234.                 repeat
  235.                     pc := pc - 1;
  236.                     if pc < 0 then
  237.                         exit(GetMacroName);
  238.                 until macros[pc] = chr(ord(MacroT));
  239.                 GetToken; {MacroT}
  240.                 GetToken; {Macro name}
  241.                 if Token = StringLiteral then begin
  242.                         len := length(TokenStr);
  243.                         if len > SymbolSize then
  244.                             len := SymbolSize;
  245.                         for i := 1 to len do
  246.                             MacroOrProcName[i] := TokenStr[i];
  247.                     end;
  248.             end;
  249.     end;
  250.  
  251.  
  252.     procedure ConvertTokenToString (t: TokenType; var str: str255);
  253.         var
  254.             i, j, len: integer;
  255.     begin
  256.         with MacrosP^ do
  257.             case token of
  258.                 semicolon: 
  259.                     str := ';';
  260.                 comma: 
  261.                     str := ',';
  262.                 colon: 
  263.                     str := ':';
  264.                 LeftParen: 
  265.                     str := '(';
  266.                 RightParen: 
  267.                     str := ')';
  268.                 LeftBracket: 
  269.                     str := '[';
  270.                 RightBracket: 
  271.                     str := ']';
  272.                 PlusOp: 
  273.                     str := '+';
  274.                 MinusOp: 
  275.                     str := '-';
  276.                 MulOp: 
  277.                     str := '*';
  278.                 DivOp: 
  279.                     str := '/';
  280.                 eqOp: 
  281.                     str := '=';
  282.                 ltOp: 
  283.                     str := '<';
  284.                 gtOp: 
  285.                     str := '>';
  286.                 neOp: 
  287.                     str := '<>';
  288.                 leOp: 
  289.                     str := '<=';
  290.                 geOp: 
  291.                     str := '>=';
  292.                 orOp: 
  293.                     str := 'or';
  294.                 IntDivOp: 
  295.                     str := 'div';
  296.                 modOp: 
  297.                     str := 'mod';
  298.                 andOp: 
  299.                     str := 'and';
  300.                 NotOp: 
  301.                     str := 'not';
  302.                 AssignOp: 
  303.                     str := ':=';
  304.                 Identifier, Variable, StringVariable, ProcIdT:  begin
  305.                         for i := 1 to SymbolSize do
  306.                             str := concat(str, SymbolTable[SymbolTableLoc].symbol[i]);
  307.                         TrimString(str);
  308.                     end;
  309.                 NumericLiteral:  begin
  310.                         if trunc(TokenValue) = TokenValue then
  311.                             RealToString(TokenValue, 1, 0, str)
  312.                         else
  313.                             RealToString(TokenValue, 1, 1, str);
  314.                     end;
  315.                 StringLiteral: 
  316.                     str := concat('''', TokenStr, '''');
  317.                 CommandT, FunctionT, StringFunctionT, ArrayT, UserCommandT, UserFuncT, UserStrFuncT: 
  318.                     for i := 1 to nSymbols do begin
  319.                             with SymbolTable[i] do
  320.                                 if (tType = token) and (MacroCommand = cType) then begin
  321.                                         for j := 1 to SymbolSize do
  322.                                             str := concat(str, symbol[j]);
  323.                                         TrimString(str);
  324.                                     end;
  325.                         end; {for}
  326.                 otherwise
  327.                     for i := 1 to nSymbols do begin
  328.                             with SymbolTable[i] do
  329.                                 if tType = token then begin
  330.                                         for j := 1 to SymbolSize do
  331.                                             str := concat(str, symbol[j]);
  332.                                         TrimString(str);
  333.                                     end;
  334.                         end; {for}
  335.             end; {case}
  336.     end;
  337.  
  338.  
  339.     procedure GetErrorLine (var ErrorLine: str255);
  340.         var
  341.             str: str255;
  342.     begin
  343.         with MacrosP^ do begin
  344.                 pc := LineStartPC;
  345.                 ErrorLine := '';
  346.                 repeat
  347.                     str := '';
  348.                     if macros[pc] = chr(ord(NewLineT)) then
  349.                         leave;
  350.                     GetToken;
  351.                     ConvertTokenToString(token, str);
  352.                     if SavePC = ErrorPC then
  353.                         str := concat('«', str, '»');
  354.                     ErrorLine := concat(ErrorLine, ' ', str);
  355.                 until token = DoneT;
  356.             end;
  357.     end;
  358.  
  359.  
  360.     procedure GetLineNumber;
  361.     begin
  362.         pc := PCStart;
  363.         MacroLineNumber := 1;
  364.         while (pc <= errorpc) and (token <> DoneT) do
  365.             GetToken;
  366.     end;
  367.  
  368.  
  369.     procedure MacroError (str: str255);
  370.   {Report run-time errors}
  371.         var
  372.             name, ErrorLine: str255;
  373.             i, count, ignore: integer;
  374.     begin
  375.         with MacrosP^ do begin
  376.                 if token = DoneT then
  377.                     exit(MacroError);
  378.                 if TopOfStack > 0 then
  379.                     DeAllocateStrings(nGlobals + 1, TopOfStack);
  380.                 ErrorPC := SavePC;
  381.                 if MacroOrProcName = BlankSymbol then
  382.                     GetMacroName;
  383.                 if MacroOrProcName[SymbolSize] <> ' ' then
  384.                     MacroOrProcName[SymbolSize] := '…';
  385.                 name := MacroOrProcName;
  386.                 TrimString(name);
  387.                 GetLineNumber;
  388.                 GetErrorLine(ErrorLine);
  389.                 InitCursor;
  390.                 ParamText(str, long2str(MacroLineNumber), Name, ErrorLine);
  391.                 Ignore := Alert(900, nil);
  392.                 Token := DoneT;
  393.             end; {with}
  394.     end;
  395.  
  396.  
  397.     procedure DoDeclaration;
  398.         var
  399.             SaveStackLoc, StackLoc: integer;
  400.     begin
  401.         SaveStackLoc := TopOfStack;
  402.         while (token = Identifier) or (token = variable) or (token = comma) or (token = StringVariable) do begin
  403.                 if token = StringVariable then begin
  404.                         MacroError('Variable previously defined');
  405.                         exit(DoDeclaration);
  406.                     end;
  407.                 if TopOfStack >= MaxStackSize then begin
  408.                         MacroError(StackOverflow);
  409.                         exit(DoDeclaration);
  410.                     end;
  411.                 TopOfStack := TopOfStack + 1;
  412.                 with MacrosP^.stack[TopOfStack] do begin
  413.                         SymbolTableIndex := SymbolTableLoc;
  414.                         value := 0.0;
  415.                         StringH := nil;
  416.                     end;
  417.                 GetToken;
  418.                 if token = comma then
  419.                     GetToken;
  420.             end; {while}
  421.         if token <> colon then
  422.             MacroError('":" expected');
  423.         GetToken;
  424.         if (token <> IntegerT) and (token <> RealT) and (token <> BooleanT) and (token <> StringT) then
  425.             MacroError('"integer", "real", "boolean" or "string" expected');
  426.         for StackLoc := SaveStackLoc + 1 to TopOfStack do
  427.             with macrosP^.stack[StackLoc] do
  428.                 case token of
  429.                     IntegerT: 
  430.                         vType := IntVar;
  431.                     RealT: 
  432.                         vType := RealVar;
  433.                     BooleanT: 
  434.                         vType := BooleanVar;
  435.                     StringT:  begin
  436.                             StringsAllocated := true;
  437.                             vType := StringVar;
  438.                             StringH := str255H(NewHandle(SizeOf(str255)));
  439.                             if StringH = nil then begin
  440.                                     MacroError('Out of memory');
  441.                                     Token := DoneT
  442.                                 end
  443.                             else
  444.                                 StringH^^ := 'Local String';
  445.                         end;
  446.                     otherwise
  447.                 end;
  448.         GetToken;
  449.         if Token = SemiColon then
  450.             GetToken;
  451.     end;
  452.  
  453.  
  454.     procedure GetLeftParen;
  455.     begin
  456.         GetToken;
  457.         if token <> LeftParen then
  458.             MacroError('"(" expected');
  459.     end;
  460.  
  461.  
  462.     procedure GetRightParen;
  463.     begin
  464.         GetToken;
  465.         if token <> RightParen then
  466.             MacroError(RightParenExpected);
  467.     end;
  468.  
  469.  
  470.     procedure GetComma;
  471.     begin
  472.         GetToken;
  473.         if token <> comma then
  474.             MacroError('"," expected');
  475.     end;
  476.  
  477.  
  478.     procedure GetArguments (var str: str255);
  479.         var
  480.             width, fwidth: integer;
  481.             i: LongInt;
  482.             isExpression, ZeroFill, noArgs: boolean;
  483.             n: extended;
  484.             str2: str255;
  485.     begin
  486.         if MacroCommand = WritelnC then begin {Check for Writeln with no arguments}
  487.                 GetToken;
  488.                 noArgs := token <> LeftParen;
  489.                 PutTokenBack;
  490.                 if NoArgs then begin
  491.                         str := '';
  492.                         exit(GetArguments);
  493.                     end;
  494.             end;
  495.         ZeroFill := not (MacroCommand in [DrawTextC, WriteC, WritelnC, PutMsgC, ShowMsgC, PutSerialC, ConcatC]);
  496.         width := 4;
  497.         fwidth := 0;
  498.         str := '';
  499.         GetLeftParen;
  500.         GetToken;
  501.         repeat
  502.             isExpression := token in [Variable, NumericLiteral, FunctionT, UserFuncT, TrueT, FalseT, ArrayT, MinusOp, LeftParen];
  503.             PutTokenBack;
  504.             if isExpression then
  505.                 n := GetExpression
  506.             else
  507.                 str2 := GetString;
  508.             GetToken;
  509.             if token = colon then begin
  510.                     width := GetInteger;
  511.                     if width < 0 then
  512.                         width := 0;
  513.                     if width > 100 then
  514.                         width := 100;
  515.                     GetToken;
  516.                     if token = colon then begin
  517.                             fwidth := GetInteger;
  518.                             if fwidth < 0 then
  519.                                 width := 0;
  520.                             if fwidth > 12 then
  521.                                 width := 12;
  522.                             GetToken;
  523.                         end;
  524.                 end;
  525.             if token = comma then
  526.                 GetToken;
  527.             if isExpression then begin
  528.                     RealToString(n, width, fwidth, str2);
  529.                     if ZeroFill and (n >= 0) then
  530.                         for i := 1 to width do
  531.                             if str2[i] = ' ' then
  532.                                 str2[i] := '0';
  533.                 end;
  534.             str := concat(str, str2);
  535.         until (token = RightParen) or (token = DoneT);
  536.     end;
  537.  
  538.  
  539.     procedure DoUserToken;
  540.     begin
  541.         MacroError('UMX package not installed');
  542.     end;
  543.  
  544.  
  545.     function DoGetString: str255; {(prompt,default:str255)}
  546.         const
  547.             StringID = 3;
  548.         var
  549.             prompt, default: str255;
  550.             Canceled: boolean;
  551.             mylog: DialogPtr;
  552.             item: integer;
  553.     begin
  554.         GetLeftParen;
  555.         prompt := GetString;
  556.         GetToken;
  557.         if token = Comma then
  558.             default := GetString
  559.         else begin
  560.                 default := '';
  561.                 PutTokenBack
  562.             end;
  563.         GetRightParen;
  564.         if Token <> DoneT then begin
  565.                 InitCursor;
  566.                 ParamText(prompt, '', '', '');
  567.                 mylog := GetNewDialog(170, nil, pointer(-1));
  568.                 SetDString(MyLog, StringID, default);
  569.                 SelIText(MyLog, StringID, 0, 32767);
  570.                 OutlineButton(MyLog, ok, 16);
  571.                 repeat
  572.                     ModalDialog(nil, item);
  573.                 until (item = ok) or (item = cancel);
  574.                 if item = ok then
  575.                     DoGetString := GetDString(MyLog, StringID)
  576.                 else begin
  577.                         DoGetString := 'cancel';
  578.                         token := DoneT;
  579.                     end;
  580.                 DisposDialog(mylog);
  581.             end;
  582.     end;
  583.  
  584.  
  585.     function GetSerial: str255;
  586.         var
  587.             count: LongInt;
  588.             buffer: packed array[1..100] of char;
  589.             err: OSErr;
  590.     begin
  591.         if SerialBufferP = nil then begin
  592.                 MacroError('Serial port not open');
  593.                 exit(GetSerial);
  594.             end;
  595.         Err := SerGetBuf(SerialIn, count);
  596.         if count > 0 then begin
  597.                 count := 1;
  598.                 Err := FSRead(SerialIn, count, @buffer);
  599.                 GetSerial := buffer[1]
  600.             end
  601.         else
  602.             GetSerial := '';
  603.     end;
  604.  
  605.  
  606.     procedure RangeCheck (i: LongInt);
  607.     begin
  608.         if (i < 0) or (i > 255) then
  609.             MacroError('Argument is less than 0 or greater than 255');
  610.     end;
  611.  
  612.  
  613.     function DoChr: str255;
  614.         var
  615.             i: LongInt;
  616.     begin
  617.         GetLeftParen;
  618.         i := GetInteger;
  619.         GetRightParen;
  620.         RangeCheck(i);
  621.         if Token <> DoneT then
  622.             DoChr := chr(i);
  623.     end;
  624.  
  625.  
  626.     function GetWindowTitle: str255;
  627.         var
  628.             wPeek: WindowPeek;
  629.     begin
  630.         wPeek := WindowPeek(FrontWindow);
  631.         if wPeek = nil then begin
  632.                 GetWindowTitle := '';
  633.                 exit(GetWindowTitle);
  634.             end;
  635.         if wPeek^.WindowKind = PicKind then
  636.             GetWindowTitle := Info^.title
  637.         else
  638.             GetWindowTitle := wPeek^.TitleHandle^^;
  639.     end;
  640.  
  641.  
  642.     function DoStringFunction: str255;
  643.         var
  644.             str: str255;
  645.     begin
  646.         case MacroCommand of
  647.             GetStringC: 
  648.                 DoStringFunction := DoGetString;
  649.             ChrC: 
  650.                 DoStringFunction := DoChr;
  651.             GetSerialC: 
  652.                 DoStringFunction := GetSerial;
  653.             ConcatC:  begin
  654.                     GetArguments(str);
  655.                     DoStringFunction := str;
  656.                 end;
  657.             WindowTitleC: 
  658.                 DoStringFunction := GetWindowTitle;
  659.             otherwise
  660.                 MacroError('"GetString ", "GetSerial" or "chr" expected');
  661.         end;
  662.     end;
  663.  
  664.  
  665.     function GetString: str255;
  666.     begin
  667.         GetToken;
  668.         if token = StringFunctionT then
  669.             GetString := DoStringFunction
  670.         else if token = UserStrFuncT then begin
  671.                 DoUserToken; {result in TokenStr}
  672.                 GetString := TokenStr;
  673.             end
  674.         else if (token = StringLiteral) or (token = StringVariable) then
  675.             GetString := TokenStr
  676.         else begin
  677.                 MacroError('String expected');
  678.                 GetString := '';
  679.             end;
  680.     end;
  681.  
  682.  
  683.     function GetInteger: LongInt;
  684.         var
  685.             n: LongInt;
  686.             r: extended;
  687.     begin
  688.         r := GetExpression;
  689.         if token = DoneT then begin
  690.                 GetInteger := 0;
  691.                 exit(GetInteger);
  692.             end;
  693.         GetInteger := round(r);
  694.     end;
  695.  
  696.  
  697.     procedure CheckBoolean (b: extended);
  698.     begin
  699.         if (b <> ord(true)) and (b <> ord(false)) then
  700.             MacroError('Boolean expression expected');
  701.     end;
  702.  
  703.  
  704.     function GetBoolean: boolean;
  705.         var
  706.             value: extended;
  707.     begin
  708.         value := GetExpression;
  709.         CheckBoolean(value);
  710.         GetBoolean := value = ord(true);
  711.     end;
  712.  
  713.  
  714.     function GetBooleanArg: boolean;
  715.     begin
  716.         GetLeftParen;
  717.         GetBooleanArg := GetBoolean;
  718.         GetRightParen;
  719.     end;
  720.  
  721.  
  722.     function GetStringArg: str255;
  723.     begin
  724.         GetLeftParen;
  725.         GetStringArg := GetString;
  726.         GetRightParen;
  727.     end;
  728.  
  729.  
  730.     procedure DoConvolve;
  731.         var
  732.             err: OSErr;
  733.             f: integer;
  734.             FileFound: boolean;
  735.             fname: str255;
  736.     begin
  737.         fname := GetStringArg;
  738.         if token <> DoneT then begin
  739.                 if (fname = '') and (CurrentWindow = TextKind) then begin
  740.                         ConvolveUsingText;
  741.                         exit(DoConvolve);
  742.                     end;
  743.                 err := fsopen(fname, KernelsRefNum, f);
  744.                 FileFound := err = NoErr;
  745.                 err := fsclose(f);
  746.                 if FileFound then
  747.                     convolve(fname, KernelsRefNum)
  748.                 else
  749.                     convolve('', 0);
  750.             end;
  751.     end;
  752.  
  753.  
  754.     function GetNumber: extended; {(prompt:str255; default:extended)}
  755.         var
  756.             prompt: str255;
  757.             default, n: extended;
  758.             Canceled: boolean;
  759.     begin
  760.         GetLeftParen;
  761.         prompt := GetString;
  762.         GetComma;
  763.         default := GetExpression;
  764.         GetRightParen;
  765.         n := 0.0;
  766.         if Token <> DoneT then begin
  767.                 n := GetReal(prompt, default, Canceled);
  768.                 if Canceled then begin
  769.                         n := default;
  770.                         token := DoneT;
  771.                     end;
  772.             end;
  773.         GetNumber := n;
  774.     end;
  775.  
  776.  
  777.     function DoGetPixel: extended; {(hloc,vloc:integer)}
  778.         var
  779.             hloc, vloc: integer;
  780.     begin
  781.         GetLeftParen;
  782.         hloc := GetInteger;
  783.         GetComma;
  784.         vloc := GetInteger;
  785.         GetRightParen;
  786.         if (Token <> DoneT) and (info <> NoInfo) then
  787.             DoGetPixel := MyGetPixel(hloc, vloc)
  788.         else
  789.             DoGetPixel := 0.0;
  790.     end;
  791.  
  792.  
  793.     function DoFunction (c: CommandType): extended;
  794.         var
  795.             n: extended;
  796.             SaveCommand: CommandType;
  797.     begin
  798.         SaveCommand := MacroCommand;
  799.         GetLeftParen;
  800.         n := GetExpression;
  801.         GetRightParen;
  802.         if Token <> DoneT then
  803.             case SaveCommand of
  804.                 truncC: 
  805.                     DoFunction := trunc(n);
  806.                 roundC: 
  807.                     DoFunction := round(n);
  808.                 oddC: 
  809.                     if odd(trunc(n)) then
  810.                         DoFunction := ord(true)
  811.                     else
  812.                         DoFunction := ord(false);
  813.                 absC: 
  814.                     DoFunction := abs(n);
  815.                 sqrtC: 
  816.                     if n < 0.0 then
  817.                         MacroError('Sqrt Error')
  818.                     else
  819.                         DoFunction := sqrt(n);
  820.                 sqrC: 
  821.                     DoFunction := sqr(n);
  822.                 sinC: 
  823.                     DoFunction := sin(n);
  824.                 cosC: 
  825.                     DoFunction := cos(n);
  826.                 expC: 
  827.                     DoFunction := exp(n);
  828.                 lnC: 
  829.                     if n <= 0.0 then
  830.                         MacroError('Log Error')
  831.                     else
  832.                         DoFunction := ln(n);
  833.                 arctanC: 
  834.                     DoFunction := arctan(n);
  835.             end
  836.         else
  837.             DoFunction := 0.0;
  838.     end;
  839.  
  840.  
  841.     function CalibrateValue: extended;
  842.         var
  843.             i: integer;
  844.     begin
  845.         GetLeftParen;
  846.         i := GetInteger;
  847.         GetRightParen;
  848.         RangeCheck(i);
  849.         if Token <> DoneT then begin
  850.                 CalibrateValue := cvalue[i];
  851.             end;
  852.     end;
  853.  
  854.  
  855.     function DoOrd: extended;
  856.         var
  857.             str: str255;
  858.     begin
  859.         GetLeftParen;
  860.         str := GetString;
  861.         GetRightParen;
  862.         if Token <> DoneT then begin
  863.                 if length(str) >= 1 then
  864.                     DoOrd := ord(str[1])
  865.                 else
  866.                     DoOrd := -1;
  867.             end;
  868.     end;
  869.  
  870.  
  871.     function DoStringToNum: extended;
  872.         var
  873.             str: str255;
  874.             n: extended;
  875.     begin
  876.         GetLeftParen;
  877.         str := GetString;
  878.         GetRightParen;
  879.         if Token <> DoneT then begin
  880.                 n := StringToReal(str);
  881.                 if n = BadReal then
  882.                     DoStringToNum := 0.0
  883.                 else
  884.                     DoStringToNum := n;
  885.             end;
  886.     end;
  887.  
  888.  
  889.     function DoLogicalFunction (c: CommandType): extended;
  890.         var
  891.             n1, n2: LongInt;
  892.     begin
  893.         GetLeftParen;
  894.         n1 := GetInteger;
  895.         GetComma;
  896.         n2 := GetInteger;
  897.         GetRightParen;
  898.         if Token <> DoneT then begin
  899.                 if c = BitAndC then
  900.                     DoLogicalFunction := band(n1, n2)
  901.                 else
  902.                     DoLogicalFunction := bor(n1, n2)
  903.             end;
  904.     end;
  905.  
  906.  
  907.     function PidExists: boolean; {(pid:integer)}
  908.         var
  909.             pid, i: integer;
  910.     begin
  911.         GetLeftParen;
  912.         pid := GetInteger;
  913.         GetRightParen;
  914.         if Token <> DoneT then begin
  915.                 PidExists := false;
  916.                 for i := 1 to nPics do
  917.                     if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = pid then begin
  918.                             PidExists := true;
  919.                             leave;
  920.                         end;
  921.             end;
  922.     end;
  923.  
  924.  
  925.     function DoPos: integer;
  926.         var
  927.             substr, str: str255;
  928.             n: extended;
  929.     begin
  930.         GetLeftParen;
  931.         substr := GetString;
  932.         GetComma;
  933.         str := GetString;
  934.         GetRightParen;
  935.         if Token <> DoneT then
  936.             DoPos := pos(substr, str);
  937.     end;
  938.  
  939.  
  940.     function ExecuteFunction: extended;
  941.     begin
  942.         case MacroCommand of
  943.             TruncC, RoundC, oddC, absC, sqrtC, sqrC, sinC, cosC, expC, lnC, arctanC: 
  944.                 ExecuteFunction := DoFunction(MacroCommand);
  945.             GetNumC: 
  946.                 ExecuteFunction := GetNumber;
  947.             RandomC: 
  948.                 ExecuteFunction := (random + 32767.0) / 65534.0;
  949.             GetPixelC: 
  950.                 ExecuteFunction := DoGetPixel;
  951.             ButtonC:  begin
  952.                     ExecuteFunction := ord(Button);
  953.                     FlushEvents(EveryEvent, 0);
  954.                 end;
  955.             nPicsC: 
  956.                 ExecuteFunction := nPics;
  957.             PicNumC: 
  958.                 ExecuteFunction := info^.PicNum;
  959.             PidNumC: 
  960.                 ExecuteFunction := info^.PidNum;
  961.             PidExistsC: 
  962.                 ExecuteFunction := ord(PidExists);
  963.             SameSizeC: 
  964.                 ExecuteFunction := ord(AllSameSize);
  965.             cValueC: 
  966.                 ExecuteFunction := CalibrateValue;
  967.             CalibratedC: 
  968.                 ExecuteFunction := ord(info^.DensityCalibrated);
  969.             rCountC: 
  970.                 ExecuteFunction := mCount;
  971.             GetSliceC: 
  972.                 with info^ do
  973.                     if StackInfo = nil then
  974.                         ExecuteFunction := 0
  975.                     else
  976.                         ExecuteFunction := Info^.StackInfo^.CurrentSlice;
  977.             nSlicesC: 
  978.                 with info^ do
  979.                     if StackInfo = nil then
  980.                         ExecuteFunction := 0
  981.                     else
  982.                         ExecuteFunction := Info^.StackInfo^.nSlices;
  983.             GetSpacingC: 
  984.                 with info^ do
  985.                     if StackInfo = nil then
  986.                         MacroError('No stack')
  987.                     else
  988.                         ExecuteFunction := Info^.StackInfo^.SliceSpacing;
  989.             nCoordinatesC: 
  990.                 ExecuteFunction := nCoordinates;
  991.             OrdC: 
  992.                 ExecuteFunction := DoOrd;
  993.             TickCountC: 
  994.                 ExecuteFunction := TickCount;
  995.             StringToNumC: 
  996.                 ExecuteFunction := DoStringToNum;
  997.             UndoSizeC: 
  998.                 ExecuteFunction := UndoBufSize;
  999.             BitAndC, BitOrC: 
  1000.                 ExecuteFunction := DoLogicalFunction(MacroCommand);
  1001.             PosC: 
  1002.                 ExecuteFunction := DoPos;
  1003.         end; {case}
  1004.     end;
  1005.  
  1006.  
  1007.     procedure CheckIndex (index: LongInt; min, max: extended);
  1008.     begin
  1009.         if (index < min) or (index > max) then
  1010.             MacroError('Array index out of range');
  1011.     end;
  1012.  
  1013.  
  1014.     function GetArrayValue: extended;
  1015.         var
  1016.             SaveCommand: CommandType;
  1017.             Index: LongInt;
  1018.             xcoord, ycoord: integer;
  1019.     begin
  1020.         SaveCommand := MacroCommand;
  1021.         GetToken;
  1022.         if token <> LeftBracket then
  1023.             MacroError('"[" expected');
  1024.         Index := GetInteger;
  1025.         GetToken;
  1026.         if token <> RightBracket then
  1027.             MacroError('"]" expected');
  1028.         case SaveCommand of
  1029.             HistogramC:  begin
  1030.                     CheckIndex(Index, 0, 255);
  1031.                     GetArrayValue := histogram[Index];
  1032.                 end;
  1033.             rAreaC:  begin
  1034.                     CheckIndex(Index, 1, MaxMeasurements);
  1035.                     GetArrayValue := mArea^[Index];
  1036.                 end;
  1037.             rMeanC:  begin
  1038.                     CheckIndex(Index, 1, MaxMeasurements);
  1039.                     GetArrayValue := mean^[Index];
  1040.                 end;
  1041.             rStdDevC:  begin
  1042.                     CheckIndex(Index, 1, MaxMeasurements);
  1043.                     GetArrayValue := sd^[Index];
  1044.                 end;
  1045.             rXC:  begin
  1046.                     CheckIndex(Index, 1, MaxMeasurements);
  1047.                     GetArrayValue := xcenter^[Index];
  1048.                 end;
  1049.             rYC:  begin
  1050.                     CheckIndex(Index, 1, MaxMeasurements);
  1051.                     GetArrayValue := ycenter^[Index];
  1052.                 end;
  1053.             rLengthC:  begin
  1054.                     CheckIndex(Index, 1, MaxMeasurements);
  1055.                     GetArrayValue := pLength^[Index];
  1056.                 end;
  1057.             rMinC:  begin
  1058.                     CheckIndex(Index, 1, MaxMeasurements);
  1059.                     GetArrayValue := mMin^[Index];
  1060.                 end;
  1061.             rMaxC:  begin
  1062.                     CheckIndex(Index, 1, MaxMeasurements);
  1063.                     GetArrayValue := mMax^[Index];
  1064.                 end;
  1065.             rMajorC:  begin
  1066.                     CheckIndex(Index, 1, MaxMeasurements);
  1067.                     GetArrayValue := MajorAxis^[Index];
  1068.                 end;
  1069.             rMinorC:  begin
  1070.                     CheckIndex(Index, 1, MaxMeasurements);
  1071.                     GetArrayValue := MinorAxis^[Index];
  1072.                 end;
  1073.             rAngleC:  begin
  1074.                     CheckIndex(Index, 1, MaxMeasurements);
  1075.                     GetArrayValue := orientation^[Index];
  1076.                 end;
  1077.             rUser1C:  begin
  1078.                     CheckIndex(Index, 1, MaxMeasurements);
  1079.                     GetArrayValue := User1^[Index];
  1080.                 end;
  1081.             rUser2C:  begin
  1082.                     CheckIndex(Index, 1, MaxMeasurements);
  1083.                     GetArrayValue := User2^[Index];
  1084.                 end;
  1085.             RedLutC, GreenLutC, BlueLutC:  begin
  1086.                     CheckIndex(Index, 0, 255);
  1087.                     if Token <> DoneT then
  1088.                         with cScreenPort^.portPixMap^^.pmTable^^.ctTable[index].rgb do
  1089.                             case SaveCommand of
  1090.                                 RedLutC: 
  1091.                                     GetArrayValue := band(bsr(red, 8), 255);
  1092.                                 GreenLutC: 
  1093.                                     GetArrayValue := band(bsr(green, 8), 255);
  1094.                                 BlueLutC: 
  1095.                                     GetArrayValue := band(bsr(blue, 8), 255);
  1096.                             end; {case}
  1097.                 end;
  1098.             BufferC:  begin
  1099.                     CheckIndex(Index, 0, MaxLine - 1);
  1100.                     if Token <> DoneT then
  1101.                         GetArrayValue := MacrosP^.aLine[index];
  1102.                 end;
  1103.             PlotDataC:  begin
  1104.                     CheckIndex(Index, 0, MaxLine - 1);
  1105.                     if Token <> DoneT then
  1106.                         GetArrayValue := PlotData^[index];
  1107.                 end;
  1108.             xCoordinatesC:  begin
  1109.                     CheckIndex(Index, 1, MaxCoordinates);
  1110.                     if Token <> DoneT then
  1111.                         with info^ do begin
  1112.                                 xcoord := xCoordinates^[index];
  1113.                                 if SpatiallyCalibrated then
  1114.                                     GetArrayValue := xcoord / xSpatialScale
  1115.                                 else
  1116.                                     GetArrayValue := xcoord
  1117.                             end;
  1118.                 end;
  1119.             yCoordinatesC:  begin
  1120.                     CheckIndex(Index, 1, MaxCoordinates);
  1121.                     if Token <> DoneT then
  1122.                         with info^ do begin
  1123.                                 ycoord := yCoordinates^[index];
  1124.                                 if InvertYCoordinates and (Info <> NoInfo) then
  1125.                                     ycoord := Info^.PicRect.bottom - ycoord - 1;
  1126.                                 if SpatiallyCalibrated then
  1127.                                     GetArrayValue := ycoord / ySpatialScale
  1128.                                 else
  1129.                                     GetArrayValue := ycoord
  1130.                             end;
  1131.                 end;
  1132.             ScionC:  begin
  1133.                     if framegrabber <> ScionLG3 then
  1134.                         MacroError('No Scion LG-3');
  1135.                     if Token <> DoneT then
  1136.                         CheckIndex(Index, 1, 4);
  1137.                     if Token <> DoneT then
  1138.                         case index of
  1139.                             1: 
  1140.                                 GetArrayValue := LG3DacA;
  1141.                             2: 
  1142.                                 GetArrayValue := LG3DacB;
  1143.                             3: 
  1144.                                 GetArrayValue := ControlReg^;
  1145.                             4: 
  1146.                                 GetArrayValue := LG3DataOut;
  1147.                         end;
  1148.                 end;
  1149.         end; {case}
  1150.     end;
  1151.  
  1152.  
  1153.     function GetStringValue: extended;
  1154.  {Convert string to a base 102 number so we can do comparisons.}
  1155.         const
  1156.             base = 102;
  1157.         var
  1158.             i, j: integer;
  1159.             v, k: extended;
  1160.     begin
  1161.         MakeLowerCase(TokenStr);
  1162.         k := 1;
  1163.         v := 0.0;
  1164.         for i := 1 to length(TokenStr) do begin
  1165.                 j := ord(TokenStr[i]);
  1166.                 if j > 127 then
  1167.                     j := 127;
  1168.                 if j >= 91 then
  1169.                     j := j - 26;
  1170.                 v := v + j * k;
  1171.                 k := k * base;
  1172.             end;
  1173.         GetStringValue := v;
  1174.     end;
  1175.  
  1176.  
  1177.     function GetValue: extended;
  1178.     begin
  1179.         case token of
  1180.             Variable, NumericLiteral: 
  1181.                 GetValue := TokenValue;
  1182.             FunctionT: 
  1183.                 GetValue := ExecuteFunction;
  1184.             StringFunctionT:  begin
  1185.                     TokenStr := DoStringFunction;
  1186.                     GetValue := GetStringValue;
  1187.                 end;
  1188.             UserFuncT:  begin
  1189.                     DoUserToken;{output in TokenValue}
  1190.                     GetValue := TokenValue;
  1191.                 end;
  1192.             UserStrFuncT:  begin
  1193.                     DoUserToken; {output in TokenStr}
  1194.                     GetValue := GetStringValue;
  1195.                 end;
  1196.             TrueT: 
  1197.                 GetValue := ord(true);
  1198.             FalseT: 
  1199.                 GetValue := ord(false);
  1200.             ArrayT: 
  1201.                 GetValue := GetArrayValue;
  1202.             StringVariable, StringLiteral: 
  1203.                 GetValue := GetStringValue;
  1204.             otherwise begin
  1205.                     MacroError('Number expected');
  1206.                     GetValue := 0.0;
  1207.                     exit(GetValue);
  1208.                 end;
  1209.         end; {case}
  1210.     end;
  1211.  
  1212.  
  1213.     function GetFactor: extended;
  1214.         var
  1215.             fValue: extended;
  1216.             isUnaryMinus, isNot: boolean;
  1217.     begin
  1218.         GetToken;
  1219.         isUnaryMinus := token = MinusOp;
  1220.         isNot := token = NotOp;
  1221.         if isUnaryMinus or isNot then
  1222.             GetToken;
  1223.         case token of
  1224.             Variable, NumericLiteral, FunctionT, StringFunctionT, UserFuncT, {}
  1225.             UserStrFuncT, TrueT, FalseT, ArrayT, StringVariable, StringLiteral: 
  1226.                 fValue := GetValue;
  1227.             LeftParen:  begin
  1228.                     fValue := GetExpression;
  1229.                     GetRightParen;
  1230.                 end;
  1231.             otherwise begin
  1232.                     macroError('Undefined identifier');
  1233.                     fvalue := 0.0
  1234.                 end;
  1235.         end;
  1236.         GetToken;
  1237.         if isUnaryMinus then
  1238.             fValue := -fValue;
  1239.         if isNot then
  1240.             if fValue = ord(true) then
  1241.                 fValue := ord(false)
  1242.             else
  1243.                 fValue := ord(true);
  1244.         GetFactor := fValue;
  1245.     end;
  1246.  
  1247.  
  1248.     function GetTerm: extended;
  1249.         var
  1250.             tValue, fValue: extended;
  1251.             op: TokenType;
  1252.     begin
  1253.         tValue := GetFactor;
  1254.         while token in [MulOp, IntDivOp, ModOp, DivOp, AndOp] do begin
  1255.                 op := token;
  1256.                 fValue := GetFactor;
  1257.                 case op of
  1258.                     MulOp: 
  1259.                         tValue := tValue * fValue;
  1260.                     IntDivOp: 
  1261.                         if fValue <> 0.0 then
  1262.                             tValue := trunc(tValue) div trunc(fValue)
  1263.                         else
  1264.                             MacroError(DivideByZero);
  1265.                     ModOp: 
  1266.                         if fValue <> 0.0 then
  1267.                             tValue := trunc(tValue) mod trunc(fValue)
  1268.                         else
  1269.                             MacroError(DivideByZero);
  1270.                     DivOp: 
  1271.                         if fValue <> 0.0 then
  1272.                             tValue := tValue / fValue
  1273.                         else
  1274.                             MacroError(DivideByZero);
  1275.                     AndOp:  begin
  1276.                             CheckBoolean(tValue);
  1277.                             CheckBoolean(fValue);
  1278.                             tValue := ord((tValue = ord(true)) and (fValue = ord(true)));
  1279.                         end;
  1280.                 end; {case}
  1281.             end; {while}
  1282.         GetTerm := tValue;
  1283.     end;
  1284.  
  1285.  
  1286.     function GetSimpleExpression: extended;
  1287.         var
  1288.             seValue, tValue: extended;
  1289.             op: TokenType;
  1290.     begin
  1291.         seValue := GetTerm;
  1292.         while token in [PlusOp, MinusOp, OrOp] do begin
  1293.                 op := token;
  1294.                 tValue := GetTerm;
  1295.                 case op of
  1296.                     PlusOp: 
  1297.                         seValue := seValue + tValue;
  1298.                     MinusOp: 
  1299.                         seValue := seValue - tValue;
  1300.                     orOp:  begin
  1301.                             CheckBoolean(seValue);
  1302.                             CheckBoolean(tValue);
  1303.                             seValue := ord((seValue = ord(true)) or (tValue = ord(true)));
  1304.                         end;
  1305.                 end;
  1306.             end;
  1307.         GetSimpleExpression := seValue;
  1308.     end;
  1309.  
  1310.  
  1311.     function GetExpression: extended;
  1312.         var
  1313.             eValue, seValue: extended;
  1314.             op: TokenType;
  1315.     begin
  1316.         eValue := GetSimpleExpression;
  1317.         while token in [eqOp, ltOp, gtOp, neOp, leOp, geOp] do begin
  1318.                 op := token;
  1319.                 seValue := GetSimpleExpression;
  1320.                 case op of
  1321.                     eqOp: 
  1322.                         eValue := ord(eValue = seValue);
  1323.                     ltOp: 
  1324.                         eValue := ord(eValue < seValue);
  1325.                     gtOp: 
  1326.                         eValue := ord(eValue > seValue);
  1327.                     neOp: 
  1328.                         eValue := ord(eValue <> seValue);
  1329.                     leOp: 
  1330.                         eValue := ord(eValue <= seValue);
  1331.                     geOp: 
  1332.                         eValue := ord(eValue >= seValue);
  1333.                 end;
  1334.             end;
  1335.         GetExpression := eValue;
  1336.         PutTokenBack;
  1337.     end;
  1338.  
  1339.  
  1340. {$S}
  1341. {Routines from here to the end of the file go in the macro1 segment}
  1342.  
  1343.     procedure DoCapture;
  1344.     begin
  1345.         CaptureAndDisplayFrame;
  1346.         if ContinuousHistogram then
  1347.             ShowContinuousHistogram;
  1348.     end;
  1349.  
  1350.  
  1351.     procedure DoWait;
  1352.         var
  1353.             seconds: extended;
  1354.             SaveTicks: LongInt;
  1355.             str: str255;
  1356.     begin
  1357.         GetLeftParen;
  1358.         seconds := GetExpression;
  1359.         GetRightParen;
  1360.         if Token <> DoneT then begin
  1361.                 SaveTicks := TickCount + round(seconds * 60.0);
  1362.                 repeat
  1363.                     if Digitizing then
  1364.                         DoCapture;
  1365.                 until (TickCount > SaveTicks) or CommandPeriod;
  1366.             end;
  1367.     end;
  1368.  
  1369.  
  1370.     procedure SetDensitySlice; {LowerLevel,UpperLevel:integer}
  1371.   {Disable density slicing if lower and upper=0 and enable it up lower and upper=255}
  1372.         var
  1373.             sStart, sEnd: integer;
  1374.     begin
  1375.         GetLeftParen;
  1376.         sStart := GetInteger;
  1377.         RangeCheck(sStart);
  1378.         GetComma;
  1379.         sEnd := GetInteger;
  1380.         RangeCheck(sEnd);
  1381.         GetRightParen;
  1382.         if Token <> DoneT then begin
  1383.                 DisableDensitySlice;
  1384.                 DisableThresholding;
  1385.                 if (sEnd < sStart) or ((sStart = 0) and (sEnd = 0)) then
  1386.                     exit(SetDensitySlice);
  1387.                 if not ((sStart = 255) and (sEnd = 255)) then begin
  1388.                         SliceStart := sStart;
  1389.                         SliceEnd := sEnd;
  1390.                         if SliceStart < 1 then
  1391.                             SliceStart := 1;
  1392.                         if SliceEnd > 254 then
  1393.                             SliceEnd := 254;
  1394.                     end;
  1395.                 EnableDensitySlice;
  1396.             end;
  1397.     end;
  1398.  
  1399.  
  1400.     procedure SetColor;
  1401.         var
  1402.             index: integer;
  1403.             SaveCommand: CommandType;
  1404.     begin
  1405.         SaveCommand := MacroCommand;
  1406.         GetLeftParen;
  1407.         index := GetInteger;
  1408.         GetRightParen;
  1409.         RangeCheck(index);
  1410.         if Token <> DoneT then begin
  1411.                 if SaveCommand = SetForeC then
  1412.                     SetForegroundColor(index)
  1413.                 else
  1414.                     SetBackgroundColor(index);
  1415.             end;
  1416.     end;
  1417.  
  1418.  
  1419.     procedure DoConstantArithmetic;
  1420.         var
  1421.             constant: extended;
  1422.             SaveCommand: CommandType;
  1423.     begin
  1424.         SaveCommand := MacroCommand;
  1425.         GetLeftParen;
  1426.         constant := GetExpression;
  1427.         GetRightParen;
  1428.         if token <> DoneT then
  1429.             case SaveCommand of
  1430.                 AddConstC: 
  1431.                     DoArithmetic(AddItem, constant);
  1432.                 MulConstC: 
  1433.                     DoArithmetic(MultiplyItem, constant);
  1434.             end;
  1435.     end;
  1436.  
  1437.  
  1438.     procedure GetNextWindow;
  1439.         var
  1440.             n: integer;
  1441.     begin
  1442.         n := info^.PicNum + 1;
  1443.         if n > nPics then
  1444.             n := 1;
  1445.         StopDigitizing;
  1446.         SaveRoi;
  1447.         DisableDensitySlice;
  1448.         SelectWindow(PicWindow[n]);
  1449.         Info := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1450.         ActivateWindow;
  1451.         GenerateValues;
  1452.         LoadLUT(info^.cTable);
  1453.         UpdatePicWindow;
  1454.     end;
  1455.  
  1456.  
  1457.     procedure DoRevert;
  1458.     begin
  1459.         if info^.revertable then begin
  1460.                 RevertToSaved;
  1461.                 UpdatePicWindow;
  1462.             end
  1463.         else
  1464.             MacroError('Unable to revert');
  1465.     end;
  1466.  
  1467.  
  1468.     procedure MakeRoi;
  1469.         var
  1470.             Left, Top, Width, Height: integer;
  1471.             SaveCommand: CommandType;
  1472.     begin
  1473.         SaveCommand := MacroCommand;
  1474.         GetLeftParen;
  1475.         left := GetInteger;
  1476.         GetComma;
  1477.         top := GetInteger;
  1478.         GetComma;
  1479.         width := GetInteger;
  1480.         if width < 1 then
  1481.             width := 1;
  1482.         GetComma;
  1483.         height := GetInteger;
  1484.         if height < 1 then
  1485.             height := 1;
  1486.         GetRightParen;
  1487.         KillRoi;
  1488.         if token <> DoneT then
  1489.             with Info^ do begin
  1490.                     StopDigitizing;
  1491.                     if SaveCommand = MakeOvalC then
  1492.                         RoiType := OvalRoi
  1493.                     else
  1494.                         RoiType := RectRoi;
  1495.                     SetRect(RoiRect, left, top, left + width, top + height);
  1496.                     MakeRegion;
  1497.                     SetupUndo;
  1498.                     RoiShowing := true;
  1499.                 end;
  1500.     end;
  1501.  
  1502.  
  1503.     procedure MoveRoi;
  1504.         var
  1505.             DeltaH, DeltaV: integer;
  1506.     begin
  1507.         GetLeftParen;
  1508.         DeltaH := GetInteger;
  1509.         GetComma;
  1510.         DeltaV := GetInteger;
  1511.         GetRightParen;
  1512.         with info^ do begin
  1513.                 if not RoiShowing then begin
  1514.                         MacroError('No Selection');
  1515.                         exit(MoveRoi);
  1516.                     end;
  1517.                 OffsetRgn(roiRgn, DeltaH, DeltaV);
  1518.                 RoiRect := roiRgn^^.rgnBBox;
  1519.                 RoiUpdateTime := 0;
  1520.                 MacroOpPending := true;
  1521.             end;
  1522.     end;
  1523.  
  1524.  
  1525.     procedure InsetRoi;
  1526.         var
  1527.             delta: integer;
  1528.     begin
  1529.         GetLeftParen;
  1530.         delta := GetInteger;
  1531.         GetRightParen;
  1532.         with info^ do begin
  1533.                 if not RoiShowing then begin
  1534.                         MacroError('No Selection');
  1535.                         exit(InsetRoi);
  1536.                     end;
  1537.                 InsetRgn(roiRgn, delta, delta);
  1538.                 RoiRect := roiRgn^^.rgnBBox;
  1539.                 RoiUpdateTime := 0;
  1540.                 MacroOpPending := true;
  1541.             end;
  1542.     end;
  1543.  
  1544.  
  1545.     procedure DoMoveTo; {(x,y:integer)}
  1546.     begin
  1547.         GetLeftParen;
  1548.         CurrentX := GetInteger;
  1549.         GetComma;
  1550.         CurrentY := GetInteger;
  1551.         GetRightParen;
  1552.         InsertionPoint.h := CurrentX;
  1553.         InsertionPoint.v := CurrentY + 4;
  1554.     end;
  1555.  
  1556.  
  1557.     procedure DoDrawtext (str: str255; EndOfLine: boolean);
  1558.     begin
  1559.         if info <> NoInfo then begin
  1560.                 KillRoi;
  1561.                 DrawTextString(str, InsertionPoint, TextJust);
  1562.                 if EndOfLine then begin
  1563.                         CurrentY := CurrentY + CurrentSize;
  1564.                         InsertionPoint.h := CurrentX;
  1565.                         InsertionPoint.v := CurrentY + 4;
  1566.                     end;
  1567.             end;
  1568.     end;
  1569.  
  1570.  
  1571.     procedure DrawNumber;
  1572.         var
  1573.             n: extended;
  1574.             str: str255;
  1575.             fwidth: integer;
  1576.     begin
  1577.         GetLeftParen;
  1578.         n := GetExpression;
  1579.         GetRightParen;
  1580.         if token <> DoneT then begin
  1581.                 if n = trunc(n) then
  1582.                     fwidth := 0
  1583.                 else
  1584.                     fwidth := precision;
  1585.                 RealToString(n, 1, fwidth, str);
  1586.                 DoDrawText(str, true);
  1587.             end;
  1588.     end;
  1589.  
  1590.  
  1591.     procedure SetFont;
  1592.         var
  1593.             FontName: str255;
  1594.             id: integer;
  1595.     begin
  1596.         FontName := GetStringArg;
  1597.         if Token <> DoneT then begin
  1598.                 GetFNum(FontName, id);
  1599.                 if id = 0 then
  1600.                     MacroError('Font not available')
  1601.                 else
  1602.                     CurrentFontID := id;
  1603.             end;
  1604.     end;
  1605.  
  1606.  
  1607.     procedure SetFontSize;
  1608.         var
  1609.             size: integer;
  1610.     begin
  1611.         GetLeftParen;
  1612.         Size := GetInteger;
  1613.         GetRightParen;
  1614.         if (size < 6) or (size > 720) then
  1615.             MacroError('Argument out of range');
  1616.         if Token <> DoneT then
  1617.             CurrentSize := size;
  1618.     end;
  1619.  
  1620.  
  1621.     procedure SetText;
  1622.         var
  1623.             Attributes: str255;
  1624.     begin
  1625.         Attributes := GetStringArg;
  1626.         if Token <> DoneT then begin
  1627.                 MakeLowerCase(Attributes);
  1628.                 if pos('with', Attributes) <> 0 then
  1629.                     TextBack := WithBack;
  1630.                 if pos('no', Attributes) <> 0 then
  1631.                     TextBack := NoBack;
  1632.                 if pos('left', Attributes) <> 0 then
  1633.                     TextJust := teJustLeft;
  1634.                 if pos('center', Attributes) <> 0 then
  1635.                     TextJust := teJustCenter;
  1636.                 if pos('right', Attributes) <> 0 then
  1637.                     TextJust := teJustRight;
  1638.                 CurrentStyle := [];
  1639.                 if pos('bold', Attributes) <> 0 then
  1640.                     CurrentStyle := CurrentStyle + [Bold];
  1641.                 if pos('italic', Attributes) <> 0 then
  1642.                     CurrentStyle := CurrentStyle + [Italic];
  1643.                 if pos('underline', Attributes) <> 0 then
  1644.                     CurrentStyle := CurrentStyle + [Underline];
  1645.                 if pos('outline', Attributes) <> 0 then
  1646.                     CurrentStyle := CurrentStyle + [Outline];
  1647.                 if pos('shadow', Attributes) <> 0 then
  1648.                     CurrentStyle := CurrentStyle + [Shadow];
  1649.             end;
  1650.     end;
  1651.  
  1652.  
  1653.     procedure DoPutMessage;
  1654.         var
  1655.             str: str255;
  1656.     begin
  1657.         GetArguments(str);
  1658.         if Token <> DoneT then
  1659.             PutMessage(str)
  1660.     end;
  1661.  
  1662.  
  1663.     function GetVar: integer;
  1664.     begin
  1665.         GetVar := 0;
  1666.         GetToken;
  1667.         if token <> Variable then
  1668.             MacroError('Variable expected')
  1669.         else
  1670.             GetVar := TokenStackLoc;
  1671.     end;
  1672.  
  1673.  
  1674.     procedure GetPicSize;  {(width,height)}
  1675.         var
  1676.             loc1, loc2: integer;
  1677.     begin
  1678.         GetLeftParen;
  1679.         loc1 := GetVar;
  1680.         GetComma;
  1681.         loc2 := GetVar;
  1682.         GetRightParen;
  1683.         if Token <> DoneT then
  1684.             with MacrosP^ do
  1685.                 if info = NoInfo then begin
  1686.                         stack[loc1].value := 0.0;
  1687.                         stack[loc2].value := 0.0;
  1688.                     end
  1689.                 else
  1690.                     with info^ do begin
  1691.                             stack[loc1].value := PixelsPerLine;
  1692.                             stack[loc2].value := nLines;
  1693.                         end;
  1694.     end;
  1695.  
  1696.  
  1697.     procedure GetRoi;  {(hloc,vloc,width,height)}
  1698.         var
  1699.             loc1, loc2, loc3, loc4: integer;
  1700.     begin
  1701.         GetLeftParen;
  1702.         loc1 := GetVar;
  1703.         GetComma;
  1704.         loc2 := GetVar;
  1705.         GetComma;
  1706.         loc3 := GetVar;
  1707.         GetComma;
  1708.         loc4 := GetVar;
  1709.         GetRightParen;
  1710.         if Token <> DoneT then
  1711.             with MacrosP^, Info^ do
  1712.                 if RoiShowing then
  1713.                     with RoiRect do begin
  1714.                             stack[loc1].value := left;
  1715.                             stack[loc2].value := top;
  1716.                             stack[loc3].value := right - left;
  1717.                             stack[loc4].value := bottom - top;
  1718.                         end
  1719.                 else begin
  1720.                         stack[loc1].value := 0.0;
  1721.                         stack[loc2].value := 0.0;
  1722.                         stack[loc3].value := 0.0;
  1723.                         stack[loc4].value := 0.0;
  1724.                     end;
  1725.     end;
  1726.  
  1727.  
  1728.     procedure CaptureOneFrame;
  1729.     begin
  1730.         if (FrameGrabber <> QuickCapture) and (FrameGrabber <> ScionLG3) then
  1731.             MacroError('Frame grabber not installed')
  1732.         else begin
  1733.                 StartDigitizing;
  1734.                 CaptureAndDisplayFrame;
  1735.                 StopDigitizing;
  1736.             end;
  1737.     end;
  1738.  
  1739.  
  1740.     procedure DoMakeNewWindow; {(name:str255)}
  1741.         var
  1742.             name: str255;
  1743.     begin
  1744.         GetArguments(name);
  1745.         if token <> DoneT then
  1746.             if (LongInt(NewPicWidth) * NewPicHeight) > UndoBufSize then
  1747.                 MacroError('New window larger than Undo buffer')
  1748.             else if not NewPicWindow(name, NewPicWidth, NewPicHeight) then
  1749.                 MacroError('Out of memory');
  1750.     end;
  1751.  
  1752.  
  1753.     procedure DoSetPalette;
  1754.         var
  1755.             PaletteType: str255;
  1756.             ok: boolean;
  1757.     begin
  1758.         PaletteType := GetStringArg;
  1759.         if token <> DoneT then begin
  1760.                 MakeLowerCase(PaletteType);
  1761.                 if pos('gray', PaletteType) <> 0 then
  1762.                     ResetGrayMap
  1763.                 else if pos('pseudo', PaletteType) <> 0 then
  1764.                     SwitchColorTables(Pseudo20Item, true)
  1765.                 else if pos('system', PaletteType) <> 0 then
  1766.                     SwitchColorTables(SystemPaletteItem, true)
  1767.                 else if pos('rainbow', PaletteType) <> 0 then
  1768.                     SwitchColorTables(RainbowItem, true)
  1769.                 else if pos('spectrum', PaletteType) <> 0 then
  1770.                     SwitchColorTables(SpectrumItem, true)
  1771.             end;
  1772.     end;
  1773.  
  1774.  
  1775.     procedure DoOpenImage;
  1776.         var
  1777.             err: OSErr;
  1778.             f: integer;
  1779.             FileFound, result: boolean;
  1780.             fname: str255;
  1781.             SaveCommand: CommandType;
  1782.     begin
  1783.         SaveCommand := MacroCommand;
  1784.         GetArguments(fname);
  1785.         if token <> DoneT then begin
  1786.                 if fname = '' then
  1787.                     fname := DefaultFileName;
  1788.                 err := fsopen(fname, DefaultRefNum, f);
  1789.                 FileFound := err = NoErr;
  1790.                 err := fsclose(f);
  1791.                 if FileFound then
  1792.                     case SaveCommand of
  1793.                         OpenC: 
  1794.                             result := DoOpen(fname, DefaultRefNum);
  1795.                         ImportC: 
  1796.                             result := ImportFile(fname, DefaultRefNum);
  1797.                     end
  1798.                 else
  1799.                     case SaveCommand of
  1800.                         OpenC: 
  1801.                             result := DoOpen('', 0);
  1802.                         ImportC: 
  1803.                             result := ImportFile('', 0);
  1804.                     end;
  1805.                 if result then
  1806.                     UpdatePicWindow
  1807.                 else
  1808.                     token := DoneT;
  1809.             end;
  1810.     end;
  1811.  
  1812.  
  1813.     procedure SetImportAttributes;
  1814.         var
  1815.             Attributes: str255;
  1816.     begin
  1817.         Attributes := GetStringArg;
  1818.         if Token <> DoneT then begin
  1819.                 MakeLowerCase(Attributes);
  1820.                 WhatToImport := ImportTIFF;
  1821.                 ImportCustomDepth := EightBits;
  1822.                 ImportSwapBytes := false;
  1823.                 ImportCalibrate := false;
  1824.                 ImportAll := false;
  1825.                 ImportAutoScale := true;
  1826.                 ImportInvert := false;
  1827.                 if pos('mcid', Attributes) <> 0 then
  1828.                     WhatToImport := ImportMCID;
  1829.                 if pos('look', Attributes) <> 0 then
  1830.                     WhatToImport := ImportLUT;
  1831.                 if pos('palette', Attributes) <> 0 then
  1832.                     WhatToImport := ImportLUT;
  1833.                 if pos('text', Attributes) <> 0 then
  1834.                     WhatToImport := ImportText;
  1835.                 if pos('custom', Attributes) <> 0 then
  1836.                     WhatToImport := ImportCustom;
  1837.                 if (pos('8', Attributes) <> 0) or (pos('eight', Attributes) <> 0) then begin
  1838.                         ImportCustomDepth := EightBits;
  1839.                         WhatToImport := ImportCustom;
  1840.                     end;
  1841.                 if (pos('signed', Attributes) <> 0) then begin
  1842.                         ImportCustomDepth := SixteenBitsSigned;
  1843.                         WhatToImport := ImportCustom;
  1844.                     end;
  1845.                 if (pos('unsigned', Attributes) <> 0) then begin
  1846.                         ImportCustomDepth := SixteenBitsUnsigned;
  1847.                         WhatToImport := ImportCustom;
  1848.                     end;
  1849.                 if (pos('swap', Attributes) <> 0) then
  1850.                     ImportSwapBytes := true;
  1851.                 if (pos('calibrate', Attributes) <> 0) then
  1852.                     ImportCalibrate := true;
  1853.                 if (pos('fixed', Attributes) <> 0) then
  1854.                     ImportAutoScale := false;
  1855.                 if (pos('all', Attributes) <> 0) then
  1856.                     ImportAll := true;
  1857.                 if (pos('invert', Attributes) <> 0) then
  1858.                     ImportInvert := true;
  1859.             end;
  1860.     end;
  1861.  
  1862.  
  1863.     procedure SetImportMinMax; {(min,max:integer)}
  1864.         var
  1865.             TempMin, TempMax: extended;
  1866.     begin
  1867.         GetLeftParen;
  1868.         TempMin := GetExpression;
  1869.         GetComma;
  1870.         TempMax := GetExpression;
  1871.         GetRightParen;
  1872.         if Token <> DoneT then begin
  1873.                 ImportAutoScale := false;
  1874.                 ImportMin := TempMin;
  1875.                 ImportMax := TempMax;
  1876.             end;
  1877.     end;
  1878.  
  1879.  
  1880.     procedure SetCustomImport; {(width,height,offset[,nslices]:integer)}
  1881.         var
  1882.             width, height, nSlices: integer;
  1883.             offset: LongInt;
  1884.     begin
  1885.         GetLeftParen;
  1886.         width := GetInteger;
  1887.         GetComma;
  1888.         height := GetInteger;
  1889.         GetComma;
  1890.         offset := GetInteger;
  1891.         GetToken;
  1892.         if token = comma then
  1893.             nSlices := GetInteger
  1894.         else begin
  1895.                 PutTokenBack;
  1896.                 nSlices := 1
  1897.             end;
  1898.         GetRightParen;
  1899.         if (width < 0) or (width > MaxPicSize) or (height < 0) or (offset < 0) or (nSlices < 1) then
  1900.             MacroError('Argument out of range');
  1901.         if Token <> DoneT then begin
  1902.                 ImportCustomWidth := width;
  1903.                 ImportCustomHeight := height;
  1904.                 ImportCustomOffset := offset;
  1905.                 ImportCustomSlices := nSlices;
  1906.                 WhatToImport := ImportCustom;
  1907.             end;
  1908.     end;
  1909.  
  1910.  
  1911.     procedure SelectImage (id: integer);
  1912.     begin
  1913.         StopDigitizing;
  1914.         SaveRoi;
  1915.         DisableDensitySlice;
  1916.         SelectWindow(PicWindow[id]);
  1917.         Info := pointer(WindowPeek(PicWindow[id])^.RefCon);
  1918.         ActivateWindow;
  1919.         GenerateValues;
  1920.         LoadLUT(info^.cTable);
  1921.         UpdatePicWindow;
  1922.     end;
  1923.  
  1924.  
  1925.     procedure SelectPic; {(PicN:integer)}
  1926.         var
  1927.             PicN, i: integer;
  1928.             SaveCommand: CommandType;
  1929.     begin
  1930.         SaveCommand := MacroCommand;
  1931.         GetLeftParen;
  1932.         PicN := GetInteger;
  1933.         GetRightParen;
  1934.         i := 0;
  1935.         while (PicN < 0) and (i < nPics) do begin
  1936.                 i := i + 1;
  1937.                 if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = PicN then
  1938.                     PicN := i;
  1939.             end;
  1940.         if (PicN < 1) or (PicN > nPics) then
  1941.             MacroError('Specified image does not exist');
  1942.         if Token <> DoneT then begin
  1943.                 if SaveCommand = SelectPicC then
  1944.                     SelectImage(PicN)
  1945.                 else
  1946.                     Info := pointer(WindowPeek(PicWindow[PicN])^.RefCon);
  1947.             end;
  1948.     end;
  1949.  
  1950.  
  1951.     procedure SetPicName;  {(name:string)}
  1952.         var
  1953.             n, i: LongInt;
  1954.             isInteger: boolean;
  1955.             name: str255;
  1956.     begin
  1957.         GetArguments(name);
  1958.         if Token <> DoneT then begin
  1959.                 with info^ do begin
  1960.                         title := name;
  1961.                         if PictureType <> FrameGrabberType then
  1962.                             PictureType := NewPicture;
  1963.                         UpdateWindowsMenuItem(PixMapSize, title, PicNum);
  1964.                         UpdateTitleBar;
  1965.                     end;
  1966.             end;
  1967.     end;
  1968.  
  1969.  
  1970.     procedure SetNewSize; {(width,height:integer)}
  1971.         var
  1972.             TempWidth, TempHeight: integer;
  1973.     begin
  1974.         GetLeftParen;
  1975.         TempWidth := GetInteger;
  1976.         GetComma;
  1977.         TempHeight := GetInteger;
  1978.         GetRightParen;
  1979.         if Token <> DoneT then begin
  1980.                 NewPicWidth := TempWidth;
  1981.                 NewPicHeight := TempHeight;
  1982.                 if odd(NewPicWidth) then
  1983.                     NewPicWidth := NewPicWidth + 1;
  1984.                 if NewPicWidth > MaxPicSize then
  1985.                     NewPicWidth := MaxPicSize;
  1986.                 if NewPicWidth < 8 then
  1987.                     NewPicWidth := 8;
  1988.                 if NewPicHeight < 8 then
  1989.                     NewPicHeight := 8;
  1990.                 if NewPicHeight > MaxPicSize then
  1991.                     NewPicHeight := MaxPicSize;
  1992.             end;
  1993.     end;
  1994.  
  1995.  
  1996.     procedure DoSaveAs;
  1997.         var
  1998.             name: str255;
  1999.             RefNum: integer;
  2000.             HasArgs: boolean;
  2001.     begin
  2002.         name := info^.title;
  2003.         if (name = 'Untitled') or (name = 'Camera') then
  2004.             name := '';
  2005.         GetToken;
  2006.         HasArgs := token = LeftParen;
  2007.         PutTokenBack;
  2008.         if HasArgs then
  2009.             GetArguments(name);
  2010.         if token <> DoneT then begin
  2011.                 StopDigitizing;
  2012.                 if nSaves = 0 then
  2013.                     RefNum := 0
  2014.                 else
  2015.                     RefNum := DefaultRefNum;
  2016.                 case CurrentWindow of
  2017.                     TextKind: 
  2018.                         SaveTextAs;
  2019.                     ResultsKind: 
  2020.                         Export('', RefNum);
  2021.                     otherwise begin
  2022.                             if info <> NoInfo then
  2023.                                 SaveAs(name, RefNum)
  2024.                             else
  2025.                                 MacroError(NoImageOpen);
  2026.                         end;
  2027.                 end;
  2028.                 nSaves := nSaves + 1;
  2029.             end;
  2030.     end;
  2031.  
  2032.  
  2033.     procedure DoSave;
  2034.         var
  2035.             kind: integer;
  2036.     begin
  2037.         StopDigitizing;
  2038.         kind := CurrentWindow;
  2039.         if (kind = PicKind) or (kind = TextKind) or (Kind = ResultsKind) then
  2040.             SaveFile
  2041.         else
  2042.             MacroError('Nothing to save');
  2043.     end;
  2044.  
  2045.  
  2046.     procedure DoExport;
  2047.         var
  2048.             name: str255;
  2049.             RefNum: integer;
  2050.             HasArgs: boolean;
  2051.     begin
  2052.         StopDigitizing;
  2053.         name := info^.title;
  2054.         if (name = 'Untitled') or (name = 'Camera') then
  2055.             name := '';
  2056.         GetToken;
  2057.         HasArgs := token = LeftParen;
  2058.         PutTokenBack;
  2059.         if HasArgs then
  2060.             GetArguments(name);
  2061.         if nSaves = 0 then
  2062.             RefNum := 0
  2063.         else
  2064.             RefNum := DefaultRefNum;
  2065.         Export(name, RefNum);
  2066.         nSaves := nSaves + 1;
  2067.     end;
  2068.  
  2069.  
  2070.     procedure DoCopyResults;
  2071.         var
  2072.             IgnoreResult: boolean;
  2073.     begin
  2074.         if mCount < 1 then
  2075.             MacroError('Copy Results failed')
  2076.         else begin
  2077.                 CopyResults;
  2078.                 IgnoreResult := SystemEdit(3); {Fake Copy needed for MultiFinder}
  2079.             end;
  2080.     end;
  2081.  
  2082.  
  2083.     procedure DisposeAll;
  2084.         var
  2085.             i, ignore: integer;
  2086.     begin
  2087.         StopDigitizing;
  2088.         for i := nPics downto 1 do begin
  2089.                 Info := pointer(WindowPeek(PicWindow[i])^.RefCon);
  2090.                 ignore := CloseAWindow(info^.wptr);
  2091.             end;
  2092.     end;
  2093.  
  2094.  
  2095.     procedure DoDuplicate;
  2096.         var
  2097.             str: str255;
  2098.     begin
  2099.         GetArguments(str);
  2100.         if token <> DoneT then
  2101.             if not Duplicate(str, false) then
  2102.                 token := DoneT
  2103.             else
  2104.                 UpdatePicWindow;
  2105.     end;
  2106.  
  2107.  
  2108.     procedure DoLineTo; {(x,y:integer)}
  2109.         var
  2110.             x, y: integer;
  2111.             p1, p2: point;
  2112.     begin
  2113.         GetLeftParen;
  2114.         p2.h := GetInteger;
  2115.         GetComma;
  2116.         p2.v := GetInteger;
  2117.         GetRightParen;
  2118.         if token <> DoneT then begin
  2119.                 KillRoi;
  2120.                 p1.h := CurrentX;
  2121.                 p1.v := CurrentY;
  2122.                 CurrentX := p2.h;
  2123.                 CurrentY := p2.v;
  2124.                 OffscreenToScreen(p1);
  2125.                 OffscreenToScreen(p2);
  2126.                 DrawObject(LineObj, p1, p2);
  2127.             end;
  2128.     end;
  2129.  
  2130.  
  2131.     procedure DoGetLine;  {(var x1,y1,x2,y2:real; LineWidth:integer)}
  2132.         var
  2133.             loc1, loc2, loc3, loc4, loc5: integer;
  2134.             x1, y1, x2, y2: real;
  2135.     begin
  2136.         GetLeftParen;
  2137.         loc1 := GetVar;
  2138.         GetComma;
  2139.         loc2 := GetVar;
  2140.         GetComma;
  2141.         loc3 := GetVar;
  2142.         GetComma;
  2143.         loc4 := GetVar;
  2144.         GetComma;
  2145.         loc5 := GetVar;
  2146.         GetRightParen;
  2147.         if Token <> DoneT then
  2148.             with MacrosP^, info^ do begin
  2149.                     GetLoi(x1, y1, x2, y2);
  2150.                     if RoiShowing and (RoiType = LineRoi) then
  2151.                         stack[loc1].value := x1
  2152.                     else
  2153.                         stack[loc1].value := -1;
  2154.                     stack[loc2].value := y1;
  2155.                     stack[loc3].value := x2;
  2156.                     stack[loc4].value := y2;
  2157.                     stack[loc5].value := LineWidth;
  2158.                 end;
  2159.     end;
  2160.  
  2161.  
  2162.     procedure DoScaleAndRotate; {(hscale,vscale,angle:real)}
  2163.         var
  2164.             SaveCommand: CommandType;
  2165.     begin
  2166.         SaveCommand := MacroCommand;
  2167.         GetLeftParen;
  2168.         rsHScale := GetExpression;
  2169.         GetComma;
  2170.         rsVScale := GetExpression;
  2171.         if SaveCommand <> ScaleSelectionC then begin
  2172.                 GetComma;
  2173.                 rsAngle := GetExpression;
  2174.             end;
  2175.         GetRightParen;
  2176.         if token <> DoneT then begin
  2177.                 if SaveCommand = ScaleSelectionC then begin
  2178.                         rsMethod := NearestNeighbor;
  2179.                         rsCreateNewWindow := false;
  2180.                         rsAngle := 0.0;
  2181.                     end;
  2182.                 ScaleAndRotate;
  2183.             end;
  2184.     end;
  2185.  
  2186.  
  2187.     procedure SetPlotScale; {(min,max:integer)}
  2188.         var
  2189.             min, max: extended;
  2190.     begin
  2191.         GetLeftParen;
  2192.         min := GetExpression;
  2193.         GetComma;
  2194.         max := GetExpression;
  2195.         GetRightParen;
  2196.         if not info^.DensityCalibrated then begin
  2197.                 RangeCheck(trunc(min));
  2198.                 RangeCheck(trunc(max));
  2199.             end;
  2200.         if token <> DoneT then begin
  2201.                 AutoScalePlots := (min = 0.0) and (max = 0.0);
  2202.                 ProfilePlotMin := min;
  2203.                 ProfilePlotMax := max;
  2204.             end;
  2205.     end;
  2206.  
  2207.  
  2208.     procedure SetPlotDimensions; {(width,height:integer)}
  2209.         var
  2210.             width, height: integer;
  2211.     begin
  2212.         GetLeftParen;
  2213.         width := GetInteger;
  2214.         GetComma;
  2215.         height := GetInteger;
  2216.         GetRightParen;
  2217.         if token <> DoneT then begin
  2218.                 FixedSizePlot := not ((width = 0) and (height = 0));
  2219.                 ProfilePlotWidth := width;
  2220.                 ProfilePlotHeight := height;
  2221.             end;
  2222.     end;
  2223.  
  2224.  
  2225.     procedure GetResults;  {(var n,mean,mode,min,max:real)}
  2226.         var
  2227.             loc1, loc2, loc3, loc4, loc5: integer;
  2228.     begin
  2229.         GetLeftParen;
  2230.         loc1 := GetVar;
  2231.         GetComma;
  2232.         loc2 := GetVar;
  2233.         GetComma;
  2234.         loc3 := GetVar;
  2235.         GetComma;
  2236.         loc4 := GetVar;
  2237.         GetComma;
  2238.         loc5 := GetVar;
  2239.         GetRightParen;
  2240.         if mCount = 0 then
  2241.             MacroError('No results');
  2242.         if Token <> DoneT then
  2243.             with MacrosP^, results do begin
  2244.                     stack[loc1].value := PixelCount^[mCount];
  2245.                     stack[loc2].value := UncalibratedMean;
  2246.                     stack[loc3].value := imode;
  2247.                     stack[loc4].value := MinIndex;
  2248.                     stack[loc5].value := MaxIndex;
  2249.                 end;
  2250.     end;
  2251.  
  2252.  
  2253.     procedure DoPasteOperation;
  2254.     begin
  2255.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  2256.                 MacroError('Not pasting');
  2257.                 exit(DoPasteOperation);
  2258.             end;
  2259.         if MacroCommand in [AddC, SubC, MulC, DivC] then begin
  2260.                 case MacroCommand of
  2261.                     AddC: 
  2262.                         CurrentOp := AddOp;
  2263.                     SubC: 
  2264.                         CurrentOp := SubtractOp;
  2265.                     MulC: 
  2266.                         CurrentOp := MultiplyOp;
  2267.                     DivC: 
  2268.                         CurrentOp := DivideOp;
  2269.                 end;
  2270.                 DoPasteMath;
  2271.                 exit(DoPasteOperation);
  2272.             end;
  2273.         case MacroCommand of
  2274.             CopyModeC: 
  2275.                 SetPasteMode(CopyModeItem);
  2276.             AndC: 
  2277.                 SetPasteMode(AndItem);
  2278.             OrC: 
  2279.                 SetPasteMode(OrItem);
  2280.             XorC: 
  2281.                 SetPasteMode(XorItem);
  2282.             ReplaceC: 
  2283.                 SetPasteMode(ReplaceItem);
  2284.             BlendC: 
  2285.                 SetPasteMode(BlendItem);
  2286.         end;
  2287.         if OptionKeyWasDown then begin
  2288.                 if PasteControl <> nil then
  2289.                     DrawPasteControl;
  2290.             end
  2291.         else
  2292.             KillRoi;
  2293.     end;
  2294.  
  2295.  
  2296.     procedure SetWidth; {(width:integer)}
  2297.         var
  2298.             width: integer;
  2299.     begin
  2300.         GetLeftParen;
  2301.         width := GetInteger;
  2302.         GetRightParen;
  2303.         if (Token <> DoneT) and (width > 0) then begin
  2304.                 LineWidth := width;
  2305.                 ShowLIneWidth;
  2306.             end;
  2307.     end;
  2308.  
  2309.  
  2310.     function GetMType (index: integer): MeasurementTypes;
  2311.     begin
  2312.         case index of
  2313.             0: 
  2314.                 GetMType := AreaM;
  2315.             1: 
  2316.                 GetMType := MeanM;
  2317.             2: 
  2318.                 GetMType := StdDevM;
  2319.             3: 
  2320.                 GetMType := xyLocM;
  2321.             4: 
  2322.                 GetMType := ModeM;
  2323.             5: 
  2324.                 GetMType := LengthM;
  2325.             6: 
  2326.                 GetMType := MajorAxisM;
  2327.             7: 
  2328.                 GetMType := MinorAxisM;
  2329.             8: 
  2330.                 GetMType := AngleM;
  2331.             9: 
  2332.                 GetMType := IntDenM;
  2333.             10: 
  2334.                 GetMType := MinMaxM;
  2335.             11: 
  2336.                 GetMType := User1M;
  2337.             12: 
  2338.                 GetMType := User2M;
  2339.         end;
  2340.     end;
  2341.  
  2342.  
  2343.     procedure SetPrecision; {(DigitsRightofDecimalPoint[,FieldWidth]:integer)}
  2344.         var
  2345.             digits, width: LongInt;
  2346.     begin
  2347.         GetLeftParen;
  2348.         digits := GetInteger;
  2349.         GetToken;
  2350.         if token = comma then
  2351.             width := GetInteger
  2352.         else
  2353.             PutTokenBack;
  2354.         GetRightParen;
  2355.         if Token <> DoneT then begin
  2356.                 if (digits >= 0) and (digits <= 12) then
  2357.                     precision := digits;
  2358.                 if (width >= 1) and (width <= 18) then
  2359.                     FieldWidth := width;
  2360.             end;
  2361.     end;
  2362.  
  2363.  
  2364.     procedure SetParticleSize; {(min,max:LongInt)}
  2365.         var
  2366.             min, max: LongInt;
  2367.     begin
  2368.         GetLeftParen;
  2369.         min := GetInteger;
  2370.         GetComma;
  2371.         max := GetInteger;
  2372.         GetRightParen;
  2373.         if Token <> DoneT then begin
  2374.                 MinParticleSize := min;
  2375.                 MaxParticleSize := max;
  2376.             end;
  2377.     end;
  2378.  
  2379.  
  2380.     procedure SetThreshold; {(level:integer)}
  2381.         var
  2382.             level: LongInt;
  2383.     begin
  2384.         GetLeftParen;
  2385.         level := GetInteger;
  2386.         GetRightParen;
  2387.         if level = -1 then begin
  2388.                 DisableThresholding;
  2389.                 exit(SetThreshold);
  2390.             end;
  2391.         RangeCheck(level);
  2392.         if Token <> DoneT then
  2393.             EnableThresholding(level);
  2394.     end;
  2395.  
  2396.  
  2397.     procedure DoPutPixel; {(hloc,vloc, value:integer)}
  2398.         var
  2399.             hloc, vloc, value: integer;
  2400.             MaskRect: rect;
  2401.     begin
  2402.         GetLeftParen;
  2403.         hloc := GetInteger;
  2404.         GetComma;
  2405.         vloc := GetInteger;
  2406.         GetComma;
  2407.         value := GetInteger;
  2408.         GetRightParen;
  2409.         if (Token <> DoneT) and (info <> NoInfo) then begin
  2410.                 KillRoi;
  2411.                 PutPixel(hloc, vloc, value);
  2412.                 SetRect(MaskRect, hloc, vloc, hloc + 1, vloc + 1);
  2413.                 UpdateScreen(MaskRect);
  2414.             end;
  2415.     end;
  2416.  
  2417.  
  2418.     procedure CloseWindow;
  2419.         var
  2420.             OldPicNum, NewPicNum, ignore: integer;
  2421.     begin
  2422.         if CurrentWindow <> PicKind then begin
  2423.                 ignore := CloseAWindow(CurrentWPtr);
  2424.                 exit(CloseWindow);
  2425.             end;
  2426.         if info = NoInfo then begin
  2427.                 MacroError(NoImageOpen);
  2428.                 exit(CloseWindow);
  2429.             end;
  2430.         StopDigitizing;
  2431.         SaveRoi;
  2432.         with info^ do begin
  2433.                 OldPicNum := PicNum;
  2434.                 ignore := CloseAWindow(wptr);
  2435.             end;
  2436.         if nPics >= 1 then begin
  2437.                 NewPicNum := OldPicNum - 1;
  2438.                 if NewPicNum < 1 then
  2439.                     NewPicNum := 1;
  2440.                 SelectImage(NewPicNum);
  2441.             end;
  2442.     end;
  2443.  
  2444.  
  2445.     procedure SetScaling;
  2446.         var
  2447.             ScalingOptions: str255;
  2448.             ok: boolean;
  2449.     begin
  2450.         ScalingOptions := GetStringArg;
  2451.         if token <> DoneT then begin
  2452.                 MakeLowerCase(ScalingOptions);
  2453.                 rsInteractive := false;
  2454.                 if pos('bilinear', ScalingOptions) <> 0 then
  2455.                     rsMethod := Bilinear;
  2456.                 if pos('nearest', ScalingOptions) <> 0 then
  2457.                     rsMethod := NearestNeighbor;
  2458.                 if pos('new', ScalingOptions) <> 0 then
  2459.                     rsCreateNewWindow := true;
  2460.                 if pos('same', ScalingOptions) <> 0 then
  2461.                     rsCreateNewWindow := false;
  2462.                 if pos('interactive', ScalingOptions) <> 0 then
  2463.                     rsInteractive := true;
  2464.             end;
  2465.     end;
  2466.  
  2467.  
  2468.     procedure DoChangeValues; {(v1,v2,v3:integer)}
  2469.         var
  2470.             v1, v2, v3: integer;
  2471.     begin
  2472.         GetLeftParen;
  2473.         v1 := GetInteger;
  2474.         GetComma;
  2475.         v2 := GetInteger;
  2476.         GetComma;
  2477.         v3 := GetInteger;
  2478.         GetRightParen;
  2479.         RangeCheck(v1);
  2480.         RangeCheck(v2);
  2481.         RangeCheck(v3);
  2482.         if Token <> DoneT then
  2483.             ChangeValues(v1, v2, v3);
  2484.     end;
  2485.  
  2486.  
  2487.     procedure DoGetMouse;  {(var x,y:integer)}
  2488.         var
  2489.             loc1, loc2, sh, sv: integer;
  2490.             loc: point;
  2491.     begin
  2492.         GetLeftParen;
  2493.         loc1 := GetVar;
  2494.         GetComma;
  2495.         loc2 := GetVar;
  2496.         GetRightParen;
  2497.         if Token <> DoneT then
  2498.             with MacrosP^ do begin
  2499.                     SetPort(info^.wptr);
  2500.                     GetMouse(loc);
  2501.                     with loc do begin
  2502.                             sh := h;
  2503.                             sv := v;
  2504.                             ScreenToOffscreen(loc);
  2505.                             if sh < 0 then
  2506.                                 h := sh;
  2507.                             if sv < 0 then
  2508.                                 v := sv;
  2509.                             stack[loc1].value := h;
  2510.                             stack[loc2].value := v;
  2511.                         end;
  2512.                 end;
  2513.     end;
  2514.  
  2515.  
  2516.     procedure DoRotate (cmd: CommandType);
  2517.         var
  2518.             NoBoolean, NewWindow: boolean;
  2519.     begin
  2520.         GetToken;
  2521.         noBoolean := token <> LeftParen;
  2522.         PutTokenBack;
  2523.         if NoBoolean then
  2524.             NewWindow := false
  2525.         else
  2526.             NewWindow := GetBooleanArg;
  2527.         if NewWindow then begin
  2528.                 case cmd of
  2529.                     RotateRC: 
  2530.                         RotateToNewWindow(RotateRight);
  2531.                     RotateLC: 
  2532.                         RotateToNewWindow(RotateLeft)
  2533.                 end;
  2534.                 if not macro then
  2535.                     MacroError('Rotate failed')
  2536.             end
  2537.         else
  2538.             case cmd of
  2539.                 RotateRC: 
  2540.                     FlipOrRotate(RotateRight);
  2541.                 RotateLC: 
  2542.                     FlipOrRotate(RotateLeft)
  2543.             end;
  2544.     end;
  2545.  
  2546.  
  2547.     procedure DoSelectSlice; {(SliceNumber:integer)}
  2548.         var
  2549.             SliceNumber: LongInt;
  2550.             isRoi: boolean;
  2551.             SaveCommand: CommandType;
  2552.     begin
  2553.         SaveCommand := MacroCommand;
  2554.         GetLeftParen;
  2555.         SliceNumber := GetInteger;
  2556.         GetRightParen;
  2557.         with info^, info^.StackInfo^ do begin
  2558.                 if (SliceNumber < 1) or (SliceNumber > nSlices) then
  2559.                     MacroError('Illegal slice number');
  2560.                 if Token <> DoneT then begin
  2561.                         isRoi := RoiShowing;
  2562.                         if isRoi then
  2563.                             KillRoi;
  2564.                         CurrentSlice := SliceNumber;
  2565.                         SelectSlice(CurrentSlice);
  2566.                         if SaveCommand = SelectSliceC then begin
  2567.                                 UpdatePicWindow;
  2568.                                 UpdateTitleBar;
  2569.                             end;
  2570.                         if isRoi then
  2571.                             RestoreRoi;
  2572.                     end;
  2573.             end;
  2574.     end;
  2575.  
  2576.  
  2577.     procedure MakeNewStack; {(name:str255)}
  2578.         var
  2579.             name: str255;
  2580.             aok: boolean;
  2581.     begin
  2582.         GetArguments(name);
  2583.         if token <> DoneT then
  2584.             if (LongInt(NewPicWidth) * NewPicHeight) > UndoBufSize then
  2585.                 MacroError('Stack larger than Undo Buffer')
  2586.             else if NewPicWindow(name, NewPicWidth, NewPicHeight) then
  2587.                 if not MakeStackFromWindow then
  2588.                     MacroError('Out of memory');
  2589.     end;
  2590.  
  2591.  
  2592.     procedure MakeLineRoi; {(x1,y1,x2,y2:real)}
  2593.         var
  2594.             x1, y1, x2, y2: real;
  2595.     begin
  2596.         GetLeftParen;
  2597.         x1 := GetExpression;
  2598.         GetComma;
  2599.         y1 := GetExpression;
  2600.         GetComma;
  2601.         x2 := GetExpression;
  2602.         GetComma;
  2603.         y2 := GetExpression;
  2604.         GetRightParen;
  2605.         if token <> DoneT then
  2606.             with Info^ do begin
  2607.                     KillRoi;
  2608.                     StopDigitizing;
  2609.                     LX1 := x1;
  2610.                     LY1 := y1;
  2611.                     LX2 := x2;
  2612.                     LY2 := y2;
  2613.                     RoiType := LineRoi;
  2614.                     MakeRegion;
  2615.                     SetupUndo;
  2616.                     RoiShowing := true;
  2617.                 end;
  2618.     end;
  2619.  
  2620.  
  2621.     procedure DoGetTime;
  2622.         var
  2623.             date: DateTimeRec;
  2624.             loc1, loc2, loc3, loc4, loc5, loc6, loc7: integer;
  2625.     begin
  2626.         GetLeftParen;
  2627.         loc1 := GetVar;
  2628.         GetComma;
  2629.         loc2 := GetVar;
  2630.         GetComma;
  2631.         loc3 := GetVar;
  2632.         GetComma;
  2633.         loc4 := GetVar;
  2634.         GetComma;
  2635.         loc5 := GetVar;
  2636.         GetComma;
  2637.         loc6 := GetVar;
  2638.         GetComma;
  2639.         loc7 := GetVar;
  2640.         GetRightParen;
  2641.         if Token <> DoneT then
  2642.             with MacrosP^, info^ do begin
  2643.                     GetTime(date);
  2644.                     with date do begin
  2645.                             stack[loc1].value := year;
  2646.                             stack[loc2].value := month;
  2647.                             stack[loc3].value := day;
  2648.                             stack[loc4].value := hour;
  2649.                             stack[loc5].value := minute;
  2650.                             stack[loc6].value := second;
  2651.                             stack[loc7].value := DayOfWeek;
  2652.                         end;
  2653.                 end;
  2654.     end;
  2655.  
  2656.  
  2657.     procedure DoSetScale; {(scale:real; unit:string)}
  2658.         var
  2659.             id: integer;
  2660.             scale: extended;
  2661.             str: str255;
  2662.     begin
  2663.         GetLeftParen;
  2664.         scale := GetExpression;
  2665.         GetComma;
  2666.         str := GetString;
  2667.         GetRightParen;
  2668.         if token <> DoneT then
  2669.             with info^ do begin
  2670.                     if str = '' then begin
  2671.                             SetScale; {Display Set Scale dialog box}
  2672.                             exit(DoSetScale);
  2673.                         end;
  2674.                     if scale < 0.0 then begin
  2675.                             MacroError('Scale<0');
  2676.                             exit(DoSetScale);
  2677.                         end;
  2678.                     MakeLowerCase(str);
  2679.                     xUnit := str;
  2680.                     xSpatialScale := scale;
  2681.                     ySpatialScale := scale;
  2682.                     PixelAspectRatio := 1.0;
  2683.                     SpatiallyCalibrated := (xUnit <> '') and (xUnit <> 'pixel') and (xUnit <> 'pixels') and (xSpatialScale <> 0.0);
  2684.                     UpdateTitleBar;
  2685.                 end;
  2686.     end;
  2687.  
  2688.  
  2689.     procedure SaveState;
  2690.     begin
  2691.         SaveForeground := ForegroundIndex;
  2692.         SaveBackground := BackgroundIndex;
  2693.         SavePicWidth := NewPicWidth;
  2694.         SavePicHeight := NewPicHeight;
  2695.         SaveMethod := rsMethod;
  2696.         SaveCreate := rsCreateNewWindow;
  2697.         SaveAngle := rsAngle;
  2698.         SaveH := rsHScale;
  2699.         SaveV := rsVScale;
  2700.         SaveInvertY := InvertYCoordinates;
  2701.         SaveScaleArithmetic := ScaleArithmetic;
  2702.         SaveScaleConvolutions := ScaleConvolutions;
  2703.     end;
  2704.  
  2705.  
  2706.     procedure RestoreState;
  2707.     begin
  2708.         if SaveForeground = -1 then
  2709.             MacroError('State not saved')
  2710.         else begin
  2711.                 SetForegroundColor(SaveForeground);
  2712.                 SetBackgroundColor(SaveBackground);
  2713.                 NewPicWidth := SavePicWidth;
  2714.                 NewPicHeight := SavePicHeight;
  2715.                 rsMethod := SaveMethod;
  2716.                 rsCreateNewWindow := SaveCreate;
  2717.                 rsAngle := SaveAngle;
  2718.                 rsHScale := SaveH;
  2719.                 rsVScale := SaveV;
  2720.                 InvertYCoordinates := SaveInvertY;
  2721.                 ScaleArithmetic := SaveScaleArithmetic;
  2722.                 ScaleConvolutions := SaveScaleConvolutions;
  2723.             end;
  2724.     end;
  2725.  
  2726.  
  2727.     procedure DoPrint;
  2728.     begin
  2729.         FindWhatToPrint;
  2730.         if WhatToPrint <> NothingToPrint then
  2731.             Print(false)
  2732.         else
  2733.             MacroError('NothingToPrint');
  2734.     end;
  2735.  
  2736.  
  2737.     procedure SetCounter; {(n:integer)}
  2738.         var
  2739.             N, i: LongInt;
  2740.     begin
  2741.         GetLeftParen;
  2742.         N := GetInteger;
  2743.         GetRightParen;
  2744.         if (N < 0) or (N > MaxMeasurements) then
  2745.             MacroError('Argument out of range');
  2746.         if Token <> DoneT then begin
  2747.                 if N = 0 then
  2748.                     ResetCounter;
  2749.                 for i := mCount + 1 to N do
  2750.                     ClearResults(i);
  2751.                 mCount := N;
  2752.                 UpdateList;
  2753.                 ShowValues;
  2754.             end;
  2755.     end;
  2756.  
  2757.  
  2758.     procedure OutputText;
  2759.         var
  2760.             NewLine: boolean;
  2761.             str: str255;
  2762.             i: integer;
  2763.             SaveCommand: CommandType;
  2764.     begin
  2765.         NewLine := MacroCommand <> WriteC;
  2766.         SaveCommand := MacroCommand;
  2767.         GetArguments(str);
  2768.         if token <> DoneT then begin
  2769.                 if SaveCommand = ShowMsgC then begin
  2770.                         for i := 1 to length(str) do
  2771.                             if str[i] = '\' then
  2772.                                 str[i] := cr;
  2773.                         ValuesMessage := str;
  2774.                         ShowValues;
  2775.                     end
  2776.                 else begin
  2777.                         if CurrentWindow = TextKind then
  2778.                             InsertText(str, NewLine)
  2779.                         else
  2780.                             DoDrawText(str, NewLine);
  2781.                     end;
  2782.             end;
  2783.     end;
  2784.  
  2785.  
  2786.     procedure SetErosionDilationCount; {(n:integer)}
  2787.         var
  2788.             n: LongInt;
  2789.     begin
  2790.         GetLeftParen;
  2791.         n := GetInteger;
  2792.         GetRightParen;
  2793.         if (n < 1) or (n > 8) then
  2794.             MacroError('Argument out of range');
  2795.         if Token <> DoneT then begin
  2796.                 BinaryCount := n;
  2797.                 BinaryThreshold := BinaryCount * 255;
  2798.             end;
  2799.     end;
  2800.  
  2801.  
  2802.     procedure SetSliceSpacing; {(n:real)}
  2803.         var
  2804.             n: real; {pixels}
  2805.     begin
  2806.         GetLeftParen;
  2807.         n := GetExpression;
  2808.         GetRightParen;
  2809.         if (n <= 0.0) or (n > 100.0) then
  2810.             MacroError('Argument out of range');
  2811.         if info^.StackInfo = nil then
  2812.             MacroError('No stack');
  2813.         if Token <> DoneT then
  2814.             info^.StackInfo^.SliceSpacing := n;
  2815.     end;
  2816.  
  2817.  
  2818.     procedure GetOrPutLineOrColumn;  {(x,y,count:integer:integer)}
  2819.         var
  2820.             x, y, count, i: integer;
  2821.             MaskRect: rect;
  2822.             aLine2: LineType;
  2823.     begin
  2824.         GetLeftParen;
  2825.         x := GetInteger;
  2826.         GetComma;
  2827.         y := GetInteger;
  2828.         GetComma;
  2829.         count := GetInteger;
  2830.         GetRightParen;
  2831.         if (Token <> DoneT) and (count <= MaxLine) then
  2832.             with MacrosP^ do begin
  2833.                     KillRoi;
  2834.                     case MacroCommand of
  2835.                         GetRowC: 
  2836.                             GetLine(x, y, count, aLine);
  2837.                         PutRowC:  begin
  2838.                                 PutLine(x, y, count, aLine);
  2839.                                 SetRect(MaskRect, x, y, x + count, y + 1);
  2840.                                 UpdateScreen(MaskRect);
  2841.                                 info^.changes := true;
  2842.                             end;
  2843.                         GetColumnC: 
  2844.                             GetColumn(x, y, count, aLine);
  2845.                         PutColumnC:  begin
  2846.                                 PutColumn(x, y, count, aLine);
  2847.                                 SetRect(MaskRect, x, y, x + 1, y + count);
  2848.                                 UpdateScreen(MaskRect);
  2849.                                 info^.changes := true;
  2850.                             end;
  2851.                     end; {case}
  2852.                 end;
  2853.     end;
  2854.  
  2855.  
  2856.     procedure CheckVersion; {(RequiredVersion:real)}
  2857.         var
  2858.             RequiredVersion: real;
  2859.             str: str255;
  2860.     begin
  2861.         GetLeftParen;
  2862.         RequiredVersion := GetExpression;
  2863.         GetRightParen;
  2864.         if (Token <> DoneT) then
  2865.             if round(RequiredVersion * 100.0) > version then begin
  2866.                     RealToString(RequiredVersion, 1, 2, str);
  2867.                     PutMessage(concat('This macro requires version ', str, ' or later of Image.'));
  2868.                     Token := DoneT;
  2869.                 end;
  2870.     end;
  2871.  
  2872.  
  2873.     procedure SetOptions; {(Options:string)}
  2874.         var
  2875.             options: str255;
  2876.             mtype: MeasurementTypes;
  2877.             i, LastOption: integer;
  2878.             SaveMeasurements: set of MeasurementTypes;
  2879.     begin
  2880.         GetLeftParen;
  2881.         Options := GetString;
  2882.         GetRightParen;
  2883.         if (Token <> DoneT) then begin
  2884.                 SaveMeasurements := measurements;
  2885.                 MakeLowerCase(options);
  2886.                 Measurements := [];
  2887.                 if pos('area', options) <> 0 then
  2888.                     Measurements := Measurements + [AreaM];
  2889.                 if pos('mean', options) <> 0 then
  2890.                     Measurements := Measurements + [MeanM];
  2891.                 if pos('st', options) <> 0 then
  2892.                     Measurements := Measurements + [StdDevM];
  2893.                 if pos('center', options) <> 0 then
  2894.                     Measurements := Measurements + [xyLocM];
  2895.                 if pos('mode', options) <> 0 then
  2896.                     Measurements := Measurements + [ModeM];
  2897.                 if (pos('per', options) <> 0) or (pos('length', options) <> 0) then
  2898.                     Measurements := Measurements + [LengthM];
  2899.                 if pos('major', options) <> 0 then
  2900.                     Measurements := Measurements + [MajorAxisM];
  2901.                 if pos('minor', options) <> 0 then
  2902.                     Measurements := Measurements + [MinorAxisM];
  2903.                 if pos('angle', options) <> 0 then
  2904.                     Measurements := Measurements + [AngleM];
  2905.                 if pos('int', options) <> 0 then
  2906.                     Measurements := Measurements + [IntDenM];
  2907.                 if pos('max', options) <> 0 then
  2908.                     Measurements := Measurements + [MinMaxM];
  2909.                 if pos('1', options) <> 0 then
  2910.                     Measurements := Measurements + [User1M];
  2911.                 if pos('2', options) <> 0 then
  2912.                     Measurements := Measurements + [User2M];
  2913.                 UpdateFitEllipse;
  2914.                 if Measurements <> SaveMeasurements then
  2915.                     UpdateList;
  2916.             end;
  2917.     end;
  2918.  
  2919.  
  2920.     procedure SetLabel;
  2921.         var
  2922.             SaveCommand: CommandType;
  2923.             str, SaveLabel: str255;
  2924.     begin
  2925.         SaveCommand := MacroCommand;
  2926.         GetArguments(str);
  2927.         case SaveCommand of
  2928.             SetMajorC:  begin
  2929.                     SaveLabel := MajorLabel;
  2930.                     MajorLabel := str;
  2931.                     Measurements := Measurements + [MajorAxisM];
  2932.                 end;
  2933.             SetMinorC:  begin
  2934.                     SaveLabel := MinorLabel;
  2935.                     MinorLabel := str;
  2936.                     Measurements := Measurements + [MinorAxisM];
  2937.                 end;
  2938.             SetUser1C:  begin
  2939.                     SaveLabel := User1Label;
  2940.                     User1Label := str;
  2941.                     Measurements := Measurements + [User1M];
  2942.                 end;
  2943.             SetUser2C:  begin
  2944.                     SaveLabel := User2Label;
  2945.                     User2Label := str;
  2946.                     Measurements := Measurements + [User2M];
  2947.                 end;
  2948.         end; {case}
  2949.         ShowValues;
  2950.         if str <> SaveLabel then
  2951.             UpdateList;
  2952.     end;
  2953.  
  2954.  
  2955.     procedure DoUpdateLUT;
  2956.     begin
  2957.         with info^ do begin
  2958.                 LoadLUT(ctable);
  2959.                 IdentityFunction := false;
  2960.                 if isGrayScaleLUT then
  2961.                     LutMode := CustomGrayScale
  2962.                 else begin
  2963.                         SetupPseudocolor;
  2964.                         LutMode := PseudoColor;
  2965.                     end;
  2966.                 UpdateMap;
  2967.             end;
  2968.     end;
  2969.  
  2970.  
  2971.     procedure SubtractBackground; {(Options:string; BallRadius:integer)}
  2972.         var
  2973.             options: str255;
  2974.             radius, item: integer;
  2975.     begin
  2976.         GetLeftParen;
  2977.         Options := GetString;
  2978.         GetComma;
  2979.         radius := GetInteger;
  2980.         GetRightParen;
  2981.         if (Token <> DoneT) then begin
  2982.                 MakeLowerCase(options);
  2983.                 FasterBackgroundSubtraction := pos('faster', options) <> 0;
  2984.                 item := Sub2DItem;
  2985.                 if pos('hor', options) <> 0 then
  2986.                     item := HorizontalItem;
  2987.                 if pos('ver', options) <> 0 then
  2988.                     item := VerticalItem;
  2989.                 if pos('roll', options) <> 0 then
  2990.                     item := Sub2DItem;
  2991.                 if pos('remove', options) <> 0 then
  2992.                     item := RemoveStreaksItem;
  2993.             end;
  2994.         BallRadius := Radius;
  2995.         if Radius < 1 then
  2996.             BallRadius := 1;
  2997.         if Radius > 319 then
  2998.             BallRadius := 319;
  2999.         DoBackgroundMenuEvent(Item);
  3000.     end;
  3001.  
  3002.  
  3003.     procedure SetExportMode;
  3004.         var
  3005.             mode: str255;
  3006.     begin
  3007.         mode := GetStringArg;
  3008.         if Token <> DoneT then begin
  3009.                 MakeLowerCase(mode);
  3010.                 ExportAsWhat := AsRaw;
  3011.                 if pos('mcid', mode) <> 0 then
  3012.                     ExportAsWhat := asMCID;
  3013.                 if pos('text', mode) <> 0 then
  3014.                     ExportAsWhat := asText;
  3015.                 if pos('lut', mode) <> 0 then
  3016.                     ExportAsWhat := asLUT;
  3017.                 if pos('meas', mode) <> 0 then
  3018.                     ExportAsWhat := asMeasurements;
  3019.                 if pos('plot', mode) <> 0 then
  3020.                     ExportAsWhat := asPlotValues;
  3021.                 if pos('hist', mode) <> 0 then
  3022.                     ExportAsWhat := asHistogramValues;
  3023.                 if pos('xy', mode) <> 0 then
  3024.                     ExportAsWhat := asCoordinates;
  3025.             end;
  3026.     end;
  3027.  
  3028.  
  3029.     procedure MoveCurrentWindow;{(x,y:integer)}
  3030.         var
  3031.             x, y: integer;
  3032.             ignore: integer;
  3033.             fwptr: WindowPtr;
  3034.             kind: integer;
  3035.     begin
  3036.         GetLeftParen;
  3037.         x := GetInteger;
  3038.         GetComma;
  3039.         y := GetInteger;
  3040.         GetRightParen;
  3041.         fwptr := FrontWindow;
  3042.         if fwptr <> nil then begin
  3043.                 kind := WindowPeek(fwptr)^.WindowKind;
  3044.                 if (kind = PicKind) or (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) or (kind = HistoKind) or (Kind = PasteControlKind) or (Kind = ResultsKind) or (Kind = TextKind) then
  3045.                     MoveWindow(fwptr, x, y, true);
  3046.             end;
  3047.     end;
  3048.  
  3049.  
  3050.     procedure DoUserCode; {str:str255; Param1,Param2,Param3:real;}
  3051.   {Contributed by Mark Vivino}
  3052.         var
  3053.             WhichCode: integer;
  3054.             Param1, Param2, Param3: extended;
  3055.             str: str255;
  3056.             NewVersion: boolean;
  3057.     begin
  3058.         GetLeftParen;
  3059.         GetToken;
  3060.         NewVersion := (token = StringLiteral) or (token = StringVariable);
  3061.         PutTokenBack;
  3062.         WhichCode := 0;
  3063.         str := '';
  3064.         if NewVersion then
  3065.             str := GetString
  3066.         else
  3067.             WhichCode := GetInteger;
  3068.         GetComma;
  3069.         Param1 := GetExpression;
  3070.         GetComma;
  3071.         Param2 := GetExpression;
  3072.         GetComma;
  3073.         Param3 := GetExpression;
  3074.         GetRightParen;
  3075.         if Token <> DoneT then begin
  3076.                 if NewVersion then
  3077.                     UserMacroCode(str, Param1, Param2, Param3)
  3078.                 else begin
  3079.                         if (WhichCode < 1) or (WhichCode > 10) then
  3080.                             MacroError('Range error . Allowable range is 1 to 10.');
  3081.                         OldUserMacroCode(WhichCode, Param1, Param2, Param3);
  3082.                     end;
  3083.             end;
  3084.     end;
  3085.  
  3086.  
  3087.     procedure CloseSerialPorts;
  3088.         var
  3089.             err: OSErr;
  3090.     begin
  3091.         if SerialBufferP <> nil then begin
  3092.                 err := CloseDriver(SerialOut);
  3093.                 err := CloseDriver(SerialIn);
  3094.                 DisposePtr(SerialBufferP);
  3095.             end;
  3096.     end;
  3097.  
  3098.  
  3099.     procedure OpenSerial;
  3100.         const
  3101.             SerialBufferSize = 1024;
  3102.         var
  3103.             err: OSErr;
  3104.             baud, data, stop, parity: integer;
  3105.             config: integer;
  3106.             flags: SerShk;
  3107.             str: str255;
  3108.     begin
  3109.         CloseSerialPorts;
  3110.         baud := baud9600;
  3111.         data := data8;
  3112.         stop := stop10;
  3113.         parity := noParity;
  3114.         str := GetStringArg;
  3115.         if token = DoneT then
  3116.             exit(OpenSerial);
  3117.         MakeLowerCase(str);
  3118.         if pos('300', str) <> 0 then
  3119.             baud := baud300;
  3120.         if pos('1200', str) <> 0 then
  3121.             baud := baud1200;
  3122.         if pos('2400', str) <> 0 then
  3123.             baud := baud2400;
  3124.         if pos('19200', str) <> 0 then
  3125.             baud := baud19200;
  3126.         if pos('two', str) <> 0 then
  3127.             stop := stop20;
  3128.         if pos('odd', str) <> 0 then
  3129.             parity := oddParity;
  3130.         if pos('even', str) <> 0 then
  3131.             parity := evenParity;
  3132.         if pos('seven', str) <> 0 then
  3133.             data := data7;
  3134.         if (OpenDriver('.AOut', SerialOut) <> NoErr) or (OpenDriver('.AIn', SerialIn) <> NoErr) then begin
  3135.                 MacroError('Error opening modem port');
  3136.                 exit(OpenSerial);
  3137.             end;
  3138.         SerialBufferP := NewPtr(SerialBufferSize);
  3139.         if SerialBufferP = nil then begin
  3140.                 MacroError('Out of Memory');
  3141.                 exit(OpenSerial);
  3142.             end;
  3143.         with flags do begin
  3144.                 fXOn := ord(false); {Disable xon/xoff output flow control}
  3145.                 fCTS := ord(false); {Disable CTS (output) flow control}
  3146.                 xOn := chr(17);
  3147.                 xOff := chr(19);
  3148.                 errs := 0;
  3149.                 evts := 0;
  3150.                 fInX := ord(true);  {Enable xon/xoff input flow control}
  3151.                 fDTR := ord(true); {Enable DTR (input) flow control}
  3152.             end;
  3153.         Config := baud + data + stop + parity;
  3154.         Err := SerHShake(SerialOut, flags);
  3155.         Err := SerSetBuf(SerialIn, SerialBufferP, SerialBufferSize);
  3156.         Err := SerReset(SerialOut, Config);
  3157.     end;
  3158.  
  3159.  
  3160.     procedure PutSerial;
  3161.         var
  3162.             i: integer;
  3163.             Size: LongInt;
  3164.             OutputBuffer: packed array[1..256] of char;
  3165.             str: str255;
  3166.             err: OSErr;
  3167.     begin
  3168.         GetArguments(str);
  3169.         if token = DoneT then
  3170.             exit(PutSerial);
  3171.         if SerialBufferP = nil then begin
  3172.                 MacroError('Serial port not open');
  3173.                 exit(PutSerial);
  3174.             end;
  3175.         Size := 0;
  3176.         for i := 1 to length(str) do begin
  3177.                 size := size + 1;
  3178.                 OutputBuffer[size] := str[i];
  3179.             end;
  3180.         if size > 0 then
  3181.             err := fswrite(SerialOut, size, @OutputBuffer);
  3182.     end;
  3183.  
  3184.  
  3185.     procedure DoSetCursor; {str: string}
  3186.         var
  3187.             str: str255;
  3188.     begin
  3189.         str := GetStringArg;
  3190.         if Token <> DoneT then begin
  3191.                 MakeLowerCase(str);
  3192.                 if pos('watch', str) <> 0 then
  3193.                     SetCursor(watch);
  3194.                 if pos('cross', str) <> 0 then
  3195.                     SetCursor(ToolCursor[SelectionTool]);
  3196.                 if pos('arrow', str) <> 0 then
  3197.                     InitCursor;
  3198.             end;
  3199.     end;
  3200.  
  3201.  
  3202.     procedure SetVideoOptions; {options: string}
  3203.         var
  3204.             options: str255;
  3205.             NewSyncMode: SyncModeType;
  3206.  
  3207.         procedure SetOption (id: integer; var option: boolean; enable: boolean);
  3208.     {Updates the modeless Video Control dialog box.}
  3209.         begin
  3210.             if option <> enable then
  3211.                 DoVideoControl(id)
  3212.         end;
  3213.  
  3214.     begin
  3215.         options := GetStringArg;
  3216.         if Token <> DoneT then begin
  3217.                 MakeLowerCase(options);
  3218.                 SetOption(InvertID, InvertVideo, pos('invert', options) <> 0);
  3219.                 SetOption(HighlightID, HighlightSaturatedPixels, pos('high', options) <> 0);
  3220.                 SetOption(OscillatingID, OscillatingMovies, pos('osc', options) <> 0);
  3221.                 SetOption(TriggerID, ExternalTrigger, pos('trig', options) <> 0);
  3222.                 SetOption(BlindID, BlindMovieCapture, pos('blind', options) <> 0);
  3223.                 if pos('sep', options) <> 0 then
  3224.                     NewSyncMode := SeparateSync
  3225.                 else
  3226.                     NewSyncMode := NormalSync;
  3227.                 if NewSyncMode <> SyncMode then
  3228.                     DoVideoControl(SyncID)
  3229.             end;
  3230.     end;
  3231.  
  3232.  
  3233.     procedure SetChannel; {(channel:integer)}
  3234.         var
  3235.             channel: integer;
  3236.     begin
  3237.         GetLeftParen;
  3238.         channel := GetInteger;
  3239.         GetRightParen;
  3240.         if (channel < 1) or (channel > 4) then
  3241.             MacroError('Bad channel number')
  3242.         else
  3243.             DoVideoControl(FirstChannelID + channel - 1);
  3244.     end;
  3245.  
  3246.  
  3247.     procedure DoAcquire;
  3248.         var
  3249.             fname: str255;
  3250.     begin
  3251.         fname := GetStringArg;
  3252.         LoadAcqPlugIn(fname);
  3253.     end;
  3254.  
  3255.  
  3256.     procedure DoFilter;
  3257.         var
  3258.             fname: str255;
  3259.     begin
  3260.         fname := GetStringArg;
  3261.         LoadFilterPlugIn(fname);
  3262.     end;
  3263.  
  3264.  
  3265.     procedure DoPhotoMode;
  3266.         var
  3267.             erase: boolean;
  3268.     begin
  3269.         erase := GetBooleanArg;
  3270.         if Token <> DoneT then begin
  3271.                 if erase then begin
  3272.                         EraseScreen;
  3273.                         UpdatePicWindow;
  3274.                         InPhotoMode := true;
  3275.                     end
  3276.                 else if InPhotoMode then begin
  3277.                         RestoreScreen;
  3278.                         InitCursor;
  3279.                     end;
  3280.             end;
  3281.     end;
  3282.  
  3283.  
  3284.     procedure RGBToIndexed; {options: string}
  3285.         var
  3286.             options: str255;
  3287.     begin
  3288.         options := GetStringArg;
  3289.         if Token <> DoneT then begin
  3290.                 MakeLowerCase(options);
  3291.                 RGBLut := CustomLUT;
  3292.                 DitherColor := false;
  3293.                 if pos('exist', options) <> 0 then
  3294.                     RGBLut := ExistingLUT;
  3295.                 if pos('system', options) <> 0 then
  3296.                     RGBLut := SystemLUT;
  3297.                 if pos('dither', options) <> 0 then
  3298.                     DitherColor := true;
  3299.                 ConvertRGBToEightBitColor(false);
  3300.             end;
  3301.     end;
  3302.  
  3303.  
  3304.     procedure DoAverageFrames; {[(Options:string; nFrames:integer)]}
  3305.         var
  3306.             options: str255;
  3307.             nFrames: integer;
  3308.             HasArguments: boolean;
  3309.     begin
  3310.         GetToken;
  3311.         HasArguments := token = LeftParen;
  3312.         PutTokenBack;
  3313.         if HasArguments then begin
  3314.                 GetLeftParen;
  3315.                 Options := GetString;
  3316.                 GetComma;
  3317.                 nFrames := GetInteger;
  3318.                 if nFrames > 0 then
  3319.                     FramesToAverage := nFrames;
  3320.                 GetRightParen;
  3321.                 if (Token <> DoneT) then begin
  3322.                         MakeLowerCase(options);
  3323.                         VideoRateAveraging := false;
  3324.                         SumFrames := false;
  3325.                         if (pos('int', options) <> 0) or (pos('sum', options) <> 0) then
  3326.                             sumFrames := true;
  3327.                         if pos('video', options) <> 0 then
  3328.                             VideoRateAveraging := true;
  3329.                     end;
  3330.             end; {has arguments}
  3331.         if token <> DoneT then
  3332.             AverageFrames;
  3333.     end;
  3334.  
  3335.  
  3336.     procedure DoSelectWindow;{('str')}
  3337.         var
  3338.             str, wTitle: str255;
  3339.             WPeek, NextWPeek: WindowPeek;
  3340.             id: integer;
  3341.             TempInfo: InfoPtr;
  3342.     begin
  3343.         GetArguments(str);
  3344.         MakeLowerCase(str);
  3345.         if Token <> DoneT then begin
  3346.                 wPeek := WindowPeek(FrontWindow);
  3347.                 while wPeek <> nil do begin
  3348.                         NextWPeek := wPeek^.NextWindow;
  3349.                         if wPeek^.WindowKind = PicKind then begin
  3350.                                 TempInfo := InfoPtr(wPeek^.RefCon);
  3351.                                 wTitle := TempInfo^.title;
  3352.                             end
  3353.                         else
  3354.                             wTitle := wPeek^.TitleHandle^^;
  3355.                         MakeLowerCase(wTitle);
  3356.                         if str = wTitle then begin
  3357.                                 if wPeek^.WindowKind = PicKind then begin
  3358.                                         info := InfoPtr(wPeek^.RefCon);
  3359.                                         with info^ do
  3360.                                             if (PicNum >= 1) and (PicNum <= nPics) then
  3361.                                                 SelectImage(PicNum);
  3362.                                     end
  3363.                                 else
  3364.                                     SelectWindow(WindowPtr(wPeek));
  3365.                                 leave;
  3366.                             end;
  3367.                         wpeek := NextWPeek;
  3368.                     end;
  3369.                 if wPeek = nil then
  3370.                     MacroError('Window not found');
  3371.             end;
  3372.     end;
  3373.  
  3374.  
  3375.     procedure GetThreshold;  {(lower,upper)}
  3376.         var
  3377.             loc1, loc2: integer;
  3378.     begin
  3379.         GetLeftParen;
  3380.         loc1 := GetVar;
  3381.         GetComma;
  3382.         loc2 := GetVar;
  3383.         GetRightParen;
  3384.         if Token <> DoneT then
  3385.             with MacrosP^ do
  3386.                 with info^ do begin
  3387.                         if Thresholding then begin
  3388.                                 stack[loc1].value := ColorStart;
  3389.                                 stack[loc2].value := 255;
  3390.                             end
  3391.                         else if DensitySlicing then begin
  3392.                                 stack[loc1].value := SliceStart;
  3393.                                 stack[loc2].value := SliceEnd;
  3394.                             end
  3395.                         else begin
  3396.                                 stack[loc1].value := 0;
  3397.                                 stack[loc2].value := 0;
  3398.                             end;
  3399.                     end;
  3400.     end;
  3401.  
  3402.  
  3403.     procedure SortPalette;
  3404.         type
  3405.             MyHSVColor = record
  3406.                     lHue, lSaturation, lValue: LongInt;
  3407.                 end;
  3408.             HSVRec = record
  3409.                     index: integer;
  3410.                     hsv: MyHSVColor;
  3411.                 end;
  3412.             HSVArrayType = array[0..255] of HSVRec;
  3413.         var
  3414.             TempTable: MyCSpecArray;
  3415.             i: integer;
  3416.             HSVArray: HSVArrayType;
  3417.             h, s, v: LongInt;
  3418.             fHue, fSaturation, fValue: fixed;
  3419.             TempHSV: HSVColor;
  3420.             table: LookupTable;
  3421.  
  3422.         procedure SortByHue;
  3423.     {Selection sorts from "Algorithms" by Robert Sedgewick.}
  3424.             var
  3425.                 i, j, min: integer;
  3426.                 t: HSVRec;
  3427.         begin
  3428.             for i := 1 to 254 do begin
  3429.                     min := i;
  3430.                     for j := i + 1 to 254 do
  3431.                         if HSVArray[j].hsv.lHue < HSVArray[min].hsv.lHue then
  3432.                             min := j;
  3433.                     t := HSVArray[min];
  3434.                     HSVArray[min] := HSVArray[i];
  3435.                     HSVArray[i] := t;
  3436.                 end;
  3437.         end;
  3438.  
  3439.     begin
  3440.         ShowWatch;
  3441.         DisableDensitySlice;
  3442.         with info^ do begin
  3443.                 for i := 1 to 254 do begin
  3444.                         HSVArray[i].index := i;
  3445.                         rgb2hsv(cTable[i].rgb, TempHSV);
  3446.                         with TempHSV do begin
  3447.                                 fHue := SmallFract2Fix(hue);
  3448.                                 fSaturation := SmallFract2Fix(saturation);
  3449.                                 fValue := SmallFract2Fix(value);
  3450.                             end;
  3451.                         with HSVArray[i].hsv do begin
  3452.                                 lHue := LongInt(band(fHue, $ffff));
  3453.                                 lSaturation := LongInt(band(fSaturation, $ffff));
  3454.                                 lValue := LongInt(band(fValue, $ffff));
  3455.                             end;
  3456.                     end;
  3457.                 SortByHue;
  3458.                 for i := 1 to 254 do
  3459.                     TempTable[i].rgb := cTable[HSVArray[i].index].rgb;
  3460.                 cTable := TempTable;
  3461.                 LoadLUT(cTable);
  3462.                 if info <> NoInfo then begin
  3463.                         table[0] := 0;
  3464.                         table[255] := 255;
  3465.                         for i := 1 to 254 do
  3466.                             table[HSVArray[i].index] := i;
  3467.                         ApplyTable(table);
  3468.                     end;
  3469.                 WhatToUndo := NothingToUndo;
  3470.                 SetupPseudocolor;
  3471.                 ColorTable := CustomTable;
  3472.             end; {with}
  3473.     end;
  3474.  
  3475.  
  3476.     procedure DoProject;
  3477.     begin
  3478.         if not (ProjectC in RoutinesCalled) then begin
  3479.                 if ShowProjectDialogBox then
  3480.                     DoProjection
  3481.                 else
  3482.                     token := DoneT;
  3483.             end
  3484.         else
  3485.             DoProjection;
  3486.         RoutinesCalled := RoutinesCalled + [ProjectC];
  3487.     end;
  3488.  
  3489.  
  3490.     procedure DoNewTextWindow; {(name,width,height)}
  3491.         var
  3492.             str: str255;
  3493.             okay, OptionalArguments: boolean;
  3494.             width, height: LongInt;
  3495.     begin
  3496.         GetLeftParen;
  3497.         str := GetString;
  3498.         GetToken;
  3499.         OptionalArguments := token <> RightParen;
  3500.         PutTokenBack;
  3501.         width := 500;
  3502.         height := 400;
  3503.         if OptionalArguments then begin
  3504.                 GetComma;
  3505.                 width := GetInteger;
  3506.                 if width < 8 then
  3507.                     width := 8;
  3508.                 GetComma;
  3509.                 height := GetInteger;
  3510.                 if height < 8 then
  3511.                     height := 8;
  3512.             end;
  3513.         GetRightParen;
  3514.         if Token <> DoneT then
  3515.             okay := MakeNewTextWindow(str, width, height);
  3516.     end;
  3517.  
  3518.  
  3519.     procedure ImageMath; {('op',pic1,pic2,gain,offset,'result')}
  3520.         var
  3521.             op, result: str255;
  3522.             pic1, pic2, offset: LongInt;
  3523.             gain: real;
  3524.     begin
  3525.         GetLeftParen;
  3526.         op := GetString;
  3527.         GetComma;
  3528.         pic1 := GetInteger;
  3529.         GetComma;
  3530.         pic2 := GetInteger;
  3531.         GetComma;
  3532.         gain := GetExpression;
  3533.         GetComma;
  3534.         offset := GetInteger;
  3535.         GetComma;
  3536.         result := GetString;
  3537.         GetRightParen;
  3538.         if token <> DoneT then begin
  3539.                 MakeLowerCase(op);
  3540.                 if pos('add', op) <> 0 then
  3541.                     CurrentMathOp := AddMath;
  3542.                 if pos('sub', op) <> 0 then
  3543.                     CurrentMathOp := SubMath;
  3544.                 if pos('mul', op) <> 0 then
  3545.                     CurrentMathOp := MulMath;
  3546.                 if pos('div', op) <> 0 then
  3547.                     CurrentMathOp := DivMath;
  3548.                 if pos('and', op) <> 0 then
  3549.                     CurrentMathOp := AndMath;
  3550.                 if pos('or', op) <> 0 then
  3551.                     CurrentMathOp := OrMath;
  3552.                 if pos('xor', op) <> 0 then
  3553.                     CurrentMathOp := XorMath;
  3554.                 if pos('max', op) <> 0 then
  3555.                     CurrentMathOp := MaxMath;
  3556.                 if pos('min', op) <> 0 then
  3557.                     CurrentMathOp := MinMath;
  3558.                 if pos('copy', op) <> 0 then
  3559.                     CurrentMathOp := CopyMath;
  3560.                 MathGain := gain;
  3561.                 MathOffset := offset;
  3562.                 DoMath(pic1, pic2, result);
  3563.             end;
  3564.     end;
  3565.  
  3566.  
  3567.     procedure PasteLive;
  3568.     begin
  3569.         with info^ do begin
  3570.                 if not RoiShowing or (RoiType <> RectRoi) then begin
  3571.                         MacroError('No selection');
  3572.                         exit(PasteLive);
  3573.                     end;
  3574.                 if PictureType = FrameGrabberType then begin
  3575.                         MacroError('Can''t paste into Camera window');
  3576.                         exit(PasteLive);
  3577.                     end;
  3578.                 if FrameGrabber = NoFrameGrabber then begin
  3579.                         MacroError('No frame grabber');
  3580.                         exit(PasteLive);
  3581.                     end;
  3582.                 SetupUndo;
  3583.                 WhatToUndo := UndoPaste;
  3584.                 ClipBufInfo^.RoiRect := RoiRect;
  3585.                 OpPending := true;
  3586.                 CurrentOp := PasteOp;
  3587.                 LivePasteMode := true;
  3588.                 WhatsOnClip := LivePic;
  3589.             end;{with}
  3590.     end;
  3591.  
  3592.  
  3593.     procedure GetPlotData;  {(var nValues,PixelsPerValue, Min,Max:real)}
  3594.         var
  3595.             loc1, loc2, loc3, loc4: integer;
  3596.     begin
  3597.         GetLeftParen;
  3598.         loc1 := GetVar;
  3599.         GetComma;
  3600.         loc2 := GetVar;
  3601.         GetComma;
  3602.         loc3 := GetVar;
  3603.         GetComma;
  3604.         loc4 := GetVar;
  3605.         GetRightParen;
  3606.         if Token <> DoneT then
  3607.             with MacrosP^, results do begin
  3608.                     ShowPlot := false;
  3609.                     PlotDensityProfile;
  3610.                     ShowPlot := true;
  3611.                     stack[loc1].value := PlotCount;
  3612.                     stack[loc2].value := PlotAvg;
  3613.                     stack[loc3].value := ActualPlotMin;
  3614.                     stack[loc4].value := ActualPlotMax;
  3615.                 end;
  3616.     end;
  3617.  
  3618.  
  3619.     procedure ExecuteCommand;
  3620.         var
  3621.             AutoSelectAll: boolean;
  3622.             t: FateTable;  {Needed for MakeSkeleton}
  3623.             okay: boolean;
  3624.             theEvent: EventRecord;
  3625.     begin
  3626.         if Info = NoInfo then
  3627.             if not (MacroCommand in LegalWithoutImage) then begin
  3628.                     MacroError('No image window active');
  3629.                     exit(ExecuteCommand);
  3630.                 end;
  3631.         if DoOption then begin
  3632.                 OptionKeyWasDown := true;
  3633.                 DoOption := false;
  3634.             end;
  3635.         if OpPending then
  3636.             if not (MacroCommand in [CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC, SetOptionC, PasteLiveC, GetRoiC, RequiresC]) then begin
  3637.                     KillRoi; {Terminate any pending paste operation.}
  3638.                     RestoreRoi;
  3639.                 end;
  3640.         MacroOpPending := false;
  3641.         case MacroCommand of
  3642.             RotateRC, RotateLC: 
  3643.                 DoRotate(MacroCommand);
  3644.             FlipVC: 
  3645.                 FlipOrRotate(FlipVertical);
  3646.             FlipHC: 
  3647.                 FlipOrRotate(FlipHorizontal);
  3648.             CopyC:  begin
  3649.                     FindWhatToCopy;
  3650.                     if WhatToCopy = NothingToCopy then
  3651.                         MacroError('Copy failed')
  3652.                     else
  3653.                         DoCopy;
  3654.                 end;
  3655.             SelectC:  begin
  3656.                     StopDigitizing;
  3657.                     SelectAll(true);
  3658.                 end;
  3659.             PasteC: 
  3660.                 DoPaste;
  3661.             ClearC, FillC, InvertC, FrameC: 
  3662.                 with info^ do begin
  3663.                         AutoSelectAll := not RoiShowing;
  3664.                         if AutoSelectAll then
  3665.                             SelectAll(true);
  3666.                         case MacroCommand of
  3667.                             ClearC: 
  3668.                                 DoOperation(EraseOp);
  3669.                             FillC: 
  3670.                                 DoOperation(PaintOp);
  3671.                             InvertC: 
  3672.                                 DoOperation(InvertOp);
  3673.                             FrameC: 
  3674.                                 DoOperation(FrameOp);
  3675.                         end;
  3676.                         UpdateScreen(RoiRect);
  3677.                         if AutoSelectAll then
  3678.                             KillRoi
  3679.                         else
  3680.                             MacroOpPending := true;
  3681.                     end;
  3682.             KillC: 
  3683.                 KillRoi;
  3684.             RestoreC: 
  3685.                 if NoInfo^.RoiType <> NoRoi then
  3686.                     RestoreRoi;
  3687.             AnalyzeC: 
  3688.                 AnalyzeParticles;
  3689.             ConvolveC: 
  3690.                 DoConvolve;
  3691.             NextC: 
  3692.                 GetNextWindow;
  3693.             MarkC: 
  3694.                 MarkSelection(mCount);
  3695.             MeasureC:  begin
  3696.                     Measure;
  3697.                     InitCursor;
  3698.                 end;
  3699.             MakeBinC: 
  3700.                 MakeBinary;
  3701.             DitherC: 
  3702.                 Filter(Dither, 0, t);
  3703.             SmoothC: 
  3704.                 if OptionKeyWasDown then
  3705.                     Filter(UnweightedAvg, 0, t)
  3706.                 else
  3707.                     Filter(WeightedAvg, 0, t);
  3708.             SharpenC: 
  3709.                 Filter(fsharpen, 0, t);
  3710.             ShadowC: 
  3711.                 Filter(fshadow, 0, t);
  3712.             TraceC: 
  3713.                 Filter(EdgeDetect, 0, t);
  3714.             ReduceC: 
  3715.                 Filter(ReduceNoise, 0, t);
  3716.             RedirectC: 
  3717.                 RedirectSampling := GetBooleanArg;
  3718.             ThresholdC: 
  3719.                 SetThreshold;
  3720.             AutoThresholdC: 
  3721.                 AutoThreshold;
  3722.             ResetgmC: 
  3723.                 ResetGrayMap;
  3724.             WaitC: 
  3725.                 DoWait;
  3726.             ResetmC: 
  3727.                 ResetCounter;
  3728.             SetSliceC: 
  3729.                 SetDensitySlice;
  3730.             UndoC: 
  3731.                 DoUndo;
  3732.             SetForeC, SetBackC: 
  3733.                 SetColor;
  3734.             HistoC:  begin
  3735.                     DoHistogram;
  3736.                     DrawHistogram;
  3737.                 end;
  3738.             EnhanceC: 
  3739.                 EnhanceContrast;
  3740.             EqualizeC: 
  3741.                 EqualizeHistogram;
  3742.             ErodeC:  begin
  3743.                     BinaryIterations := 1;
  3744.                     DoErosion;
  3745.                 end;
  3746.             DilateC:  begin
  3747.                     BinaryIterations := 1;
  3748.                     DoDilation;
  3749.                 end;
  3750.             OutlineC: 
  3751.                 filter(OutlineFilter, 0, t);
  3752.             ThinC: 
  3753.                 MakeSkeleton;
  3754.             AddConstC, MulConstC: 
  3755.                 DoConstantArithmetic;
  3756.             RevertC: 
  3757.                 DoRevert;
  3758.             BeepC: 
  3759.                 Beep;
  3760.             NopC: 
  3761.                 ;
  3762.             MakeC, MakeOvalC: 
  3763.                 MakeRoi;
  3764.             MoveC: 
  3765.                 MoveRoi;
  3766.             InsetC: 
  3767.                 InsetRoi;
  3768.             MoveToC: 
  3769.                 DoMoveTo;
  3770.             DrawTextC, WriteC, WritelnC, ShowMsgC: 
  3771.                 OutputText;
  3772.             SetFontC: 
  3773.                 SetFont;
  3774.             SetFontSizeC: 
  3775.                 SetFontSize;
  3776.             SetTextC: 
  3777.                 SetText;
  3778.             DrawNumC: 
  3779.                 DrawNumber;
  3780.             ExitC: 
  3781.                 token := DoneT;
  3782.             GetPicSizeC: 
  3783.                 GetPicSize;
  3784.             PutMsgC: 
  3785.                 DoPutMessage;
  3786.             GetRoiC: 
  3787.                 GetRoi;
  3788.             MakeNewC: 
  3789.                 DoMakeNewWindow;
  3790.             DrawScaleC: 
  3791.                 if info^.RoiShowing then begin
  3792.                         DrawScale;
  3793.                         UpdatePicWindow
  3794.                     end
  3795.                 else
  3796.                     MacroError('No Selection');
  3797.             SetPaletteC: 
  3798.                 DoSetPalette;
  3799.             OpenC, ImportC: 
  3800.                 DoOpenImage;
  3801.             SetImportC: 
  3802.                 SetImportAttributes;
  3803.             SetMinMaxC: 
  3804.                 SetImportMinMax;
  3805.             SetCustomC: 
  3806.                 SetCustomImport;
  3807.             SelectPicC, ChoosePicC: 
  3808.                 SelectPic;
  3809.             SetPicNameC: 
  3810.                 SetPicName;
  3811.             ApplyLutC: 
  3812.                 ApplyLookupTable;
  3813.             SetSizeC: 
  3814.                 SetNewSize;
  3815.             SaveC: 
  3816.                 DoSave;
  3817.             SaveAllC: 
  3818.                 SaveAll;
  3819.             SaveAsC: 
  3820.                 DoSaveAs;
  3821.             CopyResultsC: 
  3822.                 DoCopyResults;
  3823.             CloseC, DisposeC: 
  3824.                 CloseWindow;
  3825.             DisposeAllC: 
  3826.                 DisposeAll;
  3827.             DupC: 
  3828.                 DoDuplicate;
  3829.             GetInfoC: 
  3830.                 GetInfo;
  3831.             PrintC: 
  3832.                 DoPrint;
  3833.             LineToC: 
  3834.                 DoLineTo;
  3835.             GetLineC: 
  3836.                 DoGetLine;
  3837.             ShowPasteC: 
  3838.                 if PasteControl = nil then
  3839.                     ShowPasteControl
  3840.                 else
  3841.                     BringToFront(PasteControl);
  3842.             ChannelC: 
  3843.                 SetChannel;
  3844.             ColumnC, PlotProfileC:  begin
  3845.                     PlotDensityProfile;
  3846.                     if PlotWindow <> nil then
  3847.                         UpdatePlotWindow;
  3848.                 end;
  3849.             ScaleC, ScaleSelectionC: 
  3850.                 DoScaleAndRotate;
  3851.             SetOptionC: 
  3852.                 DoOption := true;
  3853.             SetLabelsC: 
  3854.                 DrawPlotLabels := GetBooleanArg;
  3855.             SetPlotScaleC: 
  3856.                 SetPlotScale;
  3857.             SetDimC: 
  3858.                 SetPlotDimensions;
  3859.             GetResultsC: 
  3860.                 GetResults;
  3861.             CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC: 
  3862.                 DoPasteOperation;
  3863.             ScaleMathC: 
  3864.                 ScaleArithmetic := GetBooleanArg;
  3865.             InvertYC: 
  3866.                 InvertYCoordinates := GetBooleanArg;
  3867.             SetWidthC: 
  3868.                 SetWidth;
  3869.             ShowResultsC:  begin
  3870.                     ShowResults;
  3871.                     UpdateList
  3872.                 end;
  3873.             StartC: 
  3874.                 StartDigitizing;
  3875.             StopC: 
  3876.                 StopDigitizing;
  3877.             CaptureC: 
  3878.                 CaptureOneFrame;
  3879.             GetRowC, PutRowC, GetColumnC, PutColumnC: 
  3880.                 GetOrPutLineOrColumn;
  3881.             PlotXYZC: 
  3882.                 PlotXYZ;
  3883.             IncludeC: 
  3884.                 IncludeHoles := GetBooleanArg;
  3885.             AutoC: 
  3886.                 WandAutoMeasure := GetBooleanArg;
  3887.             LabelC: 
  3888.                 LabelParticles := GetBooleanArg;
  3889.             OutlineParticlesC: 
  3890.                 OutlineParticles := GetBooleanArg;
  3891.             IgnoreC: 
  3892.                 IgnoreParticlesTouchingEdge := GetBooleanArg;
  3893.             AdjustC: 
  3894.                 WandAdjustAreas := GetBooleanArg;
  3895.             SetParticleSizeC: 
  3896.                 SetParticleSize;
  3897.             SetPrecisionC: 
  3898.                 SetPrecision;
  3899.             PutPixelC: 
  3900.                 DoPutPixel;
  3901.             ScalingOptionsC: 
  3902.                 SetScaling;
  3903.             SetExportC: 
  3904.                 SetExportMode;
  3905.             ExportC: 
  3906.                 DoExport;
  3907.             ChangeC: 
  3908.                 DoChangeValues;
  3909.             UpdateResultsC:  begin
  3910.                     ShowValues;
  3911.                     DeleteLines(mCount, mCount);
  3912.                     AppendResults;
  3913.                 end;
  3914.             TileC: 
  3915.                 TileImages;
  3916.             SetMajorC, SetMinorC, SetUser1C, SetUser2C: 
  3917.                 SetLabel;
  3918.             GetMouseC: 
  3919.                 DoGetMouse;
  3920.             SelectSliceC, ChooseSliceC, AddSliceC, DeleteSliceC, ResliceC:  begin
  3921.                     if info^.StackInfo = nil then
  3922.                         MacroError('No stack');
  3923.                     if token <> DoneT then
  3924.                         case MacroCommand of
  3925.                             SelectSliceC, ChooseSliceC: 
  3926.                                 DoSelectSlice;
  3927.                             AddSliceC: 
  3928.                                 okay := AddSlice(true);
  3929.                             DeleteSliceC: 
  3930.                                 DeleteSlice;
  3931.                             ResliceC: 
  3932.                                 Reslice;
  3933.                         end;
  3934.                 end;
  3935.             MakeStackC: 
  3936.                 MakeNewStack;
  3937.             AverageFramesC: 
  3938.                 DoAverageFrames;
  3939.             TriggerC: 
  3940.                 WaitForTrigger;
  3941.             MakeLineC: 
  3942.                 MakeLineRoi;
  3943.             GetTimeC: 
  3944.                 DoGetTime;
  3945.             SetScaleC: 
  3946.                 DoSetScale;
  3947.             SaveStateC: 
  3948.                 SaveState;
  3949.             RestoreStateC: 
  3950.                 RestoreState;
  3951.             SetCounterC: 
  3952.                 SetCounter;
  3953.             UpdateLutC: 
  3954.                 DoUpdateLUT;
  3955.             SetCountC: 
  3956.                 SetErosionDilationCount;
  3957.             PropagateLutC: 
  3958.                 DoPropagate(1);
  3959.             PropagateSpatialC: 
  3960.                 DoPropagate(2);
  3961.             PropagateDensityC: 
  3962.                 DoPropagate(3);
  3963.             SetSpacingC: 
  3964.                 SetSliceSpacing;
  3965.             RequiresC: 
  3966.                 CheckVersion;
  3967.             SetOptionsC: 
  3968.                 SetOptions;
  3969.             SubtractBackgroundC: 
  3970.                 SubtractBackground;
  3971.             MoveWindowC: 
  3972.                 MoveCurrentWindow;
  3973.             UserCodeC: 
  3974.                 DoUserCode;
  3975.             InvertLutC:  begin
  3976.                     InvertPalette;
  3977.                     UpdateLUT;
  3978.                 end;
  3979.             OpenSerialC: 
  3980.                 OpenSerial;
  3981.             PutSerialC: 
  3982.                 PutSerial;
  3983.             SetCursorC: 
  3984.                 DoSetCursor;
  3985.             SetVideoC: 
  3986.                 SetVideoOptions;
  3987.             AcquireC: 
  3988.                 DoAcquire;
  3989.             FilterC: 
  3990.                 DoFilter;
  3991.             PhotoModeC: 
  3992.                 DoPhotoMode;
  3993.             RGBToIndexedC: 
  3994.                 RGBToIndexed;
  3995.             SurfacePlotC: 
  3996.                 PlotSurface;
  3997.             SelectWindowC: 
  3998.                 DoSelectWindow;
  3999.             NewTextWindowC: 
  4000.                 DoNewTextWindow;
  4001.             CaptureColorC: 
  4002.                 CaptureColor;
  4003.             GetThresholdC: 
  4004.                 GetThreshold;
  4005.             AverageSlicesC: 
  4006.                 AverageSlices;
  4007.             SortPaletteC: 
  4008.                 SortPalette;
  4009.             ProjectC: 
  4010.                 DoProject;
  4011.             ScaleConvolutionsC: 
  4012.                 ScaleConvolutions := GetBooleanArg;
  4013.             ImageMathC: 
  4014.                 ImageMath;
  4015.             PasteLiveC: 
  4016.                 PasteLive;
  4017.             GetPlotDataC: 
  4018.                 GetPlotData;
  4019.         end; {case}
  4020.         OptionKeyWasDown := false;
  4021.         if not macro then begin
  4022.                 Token := DoneT;
  4023.                 KillRoi;
  4024.             end;
  4025.         if TickCount > MacroTicks then begin
  4026.                 MacroTicks := TickCount + 10;
  4027.                 if EventAvail(everyEvent, theEvent) then
  4028.                     ; {Allows background tasks to run}
  4029.                 if CommandPeriod then begin
  4030.                         Token := DoneT;
  4031.                         KillRoi;
  4032.                     end;
  4033.             end;
  4034.     end;
  4035.  
  4036.  
  4037.     procedure DoCompoundStatement;
  4038.     begin
  4039.         if token <> BeginT then
  4040.             MacroError('"begin" expected');
  4041.         GetToken;
  4042.         while (token <> endT) and (token <> DoneT) do begin
  4043.                 DoStatement;
  4044.                 GetToken;
  4045.                 if Token = SemiColon then
  4046.                     GetToken
  4047.                 else if token <> EndT then
  4048.                     MacroError(EndExpected);
  4049.             end;
  4050.     end;
  4051.  
  4052.  
  4053.     procedure SkipCompoundStatement;
  4054.         var
  4055.             count: integer;
  4056.     begin
  4057.         count := 1;
  4058.         repeat
  4059.             GetToken;
  4060.             case token of
  4061.                 beginT: 
  4062.                     count := count + 1;
  4063.                 endT: 
  4064.                     count := count - 1;
  4065.                 DoneT:  begin
  4066.                         MacroError('"end" expected');
  4067.                         exit(SkipCompoundStatement);
  4068.                     end;
  4069.                 otherwise
  4070.             end; {case}
  4071.         until count = 0;
  4072.     end;
  4073.  
  4074.  
  4075.     procedure DoDeclarations;
  4076.     begin
  4077.         if token = SemiColon then
  4078.             GetToken;
  4079.         if token = VarT then begin
  4080.                 GetToken;
  4081.                 while ((token = Identifier) or (token = variable) or (token = StringVariable)) and (Token <> DoneT) do
  4082.                     DoDeclaration;
  4083.             end;
  4084.     end;
  4085.  
  4086.  
  4087.     procedure DoFor;
  4088.         var
  4089.             SavePC, StackLoc: integer;
  4090.             StartValue, EndValue, i: LongInt;
  4091.     begin
  4092.         StackLoc := GetVar;
  4093.         GetToken;
  4094.         if token <> AssignOp then begin
  4095.                 MacroError('":=" expected');
  4096.                 exit(DoFor);
  4097.             end;
  4098.         StartValue := GetInteger;
  4099.         if token = DoneT then
  4100.             exit(DoFor);
  4101.         GetToken;
  4102.         if token <> ToT then begin
  4103.                 MacroError('"to" expected');
  4104.                 exit(DoFor);
  4105.             end;
  4106.         EndValue := GetInteger;
  4107.         if token = DoneT then
  4108.             exit(DoFor);
  4109.         GetToken;
  4110.         if token <> DoT then begin
  4111.                 MacroError(DoExpected);
  4112.                 exit(DoFor);
  4113.             end;
  4114.         SavePC := pc;
  4115.         if StartValue > EndValue then begin
  4116.                 GetToken;
  4117.                 SkipStatement
  4118.             end
  4119.         else
  4120.             for i := StartValue to EndValue do
  4121.                 with MacrosP^ do begin
  4122.                         Stack[StackLoc].value := i;
  4123.                         pc := SavePC;
  4124.                         GetToken;
  4125.                         DoStatement;
  4126.                         if CommandPeriod then
  4127.                             token := DoneT;
  4128.                         if Token = DoneT then
  4129.                             leave;
  4130.                         if Digitizing then
  4131.                             DoCapture;
  4132.                     end;
  4133.     end;
  4134.  
  4135.  
  4136.     procedure SkipFor;
  4137.     begin
  4138.         GetToken;
  4139.         SkipPartialStatement;
  4140.         GetToken;
  4141.         if token <> doT then
  4142.             MacroError(DoExpected);
  4143.         GetToken;
  4144.         SkipStatement
  4145.     end;
  4146.  
  4147.  
  4148.     procedure DoAssignment;
  4149.         var
  4150.             SaveStackLoc: integer;
  4151.     begin
  4152.         SaveStackLoc := TokenStackLoc;
  4153.         GetToken;
  4154.         if token <> AssignOp then begin
  4155.                 MacroError('":=" expected');
  4156.                 exit(DoAssignment);
  4157.             end;
  4158.         MacrosP^.stack[SaveStackLoc].value := GetExpression;
  4159.     end;
  4160.  
  4161.  
  4162.     procedure DoStringAssignment;
  4163.         var
  4164.             SaveStackLoc: integer;
  4165.             str: Str255;
  4166.     begin
  4167.         SaveStackLoc := TokenStackLoc;
  4168.         GetToken;
  4169.         if token <> AssignOp then begin
  4170.                 MacroError('":=" expected');
  4171.                 exit(DoStringAssignment);
  4172.             end;
  4173.         str := GetString;
  4174.         if token <> DoneT then
  4175.             with MacrosP^.stack[SaveStackLoc] do
  4176.                 if StringH <> nil then
  4177.                     StringH^^ := str;
  4178.     end;
  4179.  
  4180.  
  4181.     procedure SkipPartialStatement;
  4182.         var
  4183.             done: Boolean;
  4184.     begin
  4185.         done := token = DoneT;
  4186.         while not done do begin
  4187.                 case token of
  4188.                     ThenT, DoT, SemiColon, EndT, ElseT, UntilT:  begin
  4189.                             PutTokenBack;
  4190.                             done := true;
  4191.                         end;
  4192.                     DoneT, BeginT, ForT, IfT, WhileT, RepeatT:  begin
  4193.                             MacroError('end of statement expected');
  4194.                             done := true;
  4195.                         end;
  4196.                     otherwise
  4197.                         GetToken;
  4198.                 end;
  4199.             end;
  4200.     end;
  4201.  
  4202.  
  4203.     procedure DoIf;
  4204.         var
  4205.             isTrue: boolean;
  4206.     begin
  4207.         isTrue := GetBoolean;
  4208.         GetToken;
  4209.         if token <> ThenT then
  4210.             MacroError(ThenExpected);
  4211.         if isTrue then begin
  4212.                 GetToken;
  4213.                 DoStatement
  4214.             end
  4215.         else begin
  4216.                 GetToken;
  4217.                 SkipStatement;
  4218.             end;
  4219.         GetToken;
  4220.         if token = elseT then begin
  4221.                 if isTrue then begin
  4222.                         GetToken;
  4223.                         SkipStatement
  4224.                     end
  4225.                 else begin
  4226.                         GetToken;
  4227.                         DoStatement;
  4228.                     end;
  4229.             end
  4230.         else
  4231.             PutTokenBack;
  4232.     end;
  4233.  
  4234.  
  4235.     procedure SkipIf;
  4236.     begin
  4237.         GetToken;
  4238.         SkipPartialStatement;
  4239.         GetToken;
  4240.         if token <> thenT then
  4241.             MacroError(ThenExpected);
  4242.         GetToken;
  4243.         SkipStatement;
  4244.         GetToken;
  4245.         if token <> elseT then
  4246.             PutTokenBack
  4247.         else begin
  4248.                 GetToken;
  4249.                 SkipStatement
  4250.             end
  4251.     end;
  4252.  
  4253.  
  4254.     procedure DoWhile;
  4255.         var
  4256.             isTrue: boolean;
  4257.             SavePC: integer;
  4258.     begin
  4259.         SavePC := pc;
  4260.         repeat
  4261.             pc := SavePC;
  4262.             isTrue := GetBoolean;
  4263.             GetToken;
  4264.             if token <> doT then
  4265.                 MacroError(DoExpected);
  4266.             if isTrue then begin
  4267.                     GetToken;
  4268.                     DoStatement
  4269.                 end
  4270.             else begin
  4271.                     GetToken;
  4272.                     SkipStatement;
  4273.                 end;
  4274.             if Digitizing then
  4275.                 DoCapture;
  4276.             if CommandPeriod then
  4277.                 token := DoneT;
  4278.         until not isTrue or (Token = DoneT);
  4279.     end;
  4280.  
  4281.  
  4282.     procedure SkipWhile;
  4283.     begin
  4284.         GetToken;
  4285.         SkipPartialStatement;
  4286.         GetToken;
  4287.         if token <> doT then
  4288.             MacroError(DoExpected);
  4289.         GetToken;
  4290.         SkipStatement
  4291.     end;
  4292.  
  4293.  
  4294.     procedure DoRepeat;
  4295.         var
  4296.             isTrue: boolean;
  4297.             SavePC: integer;
  4298.     begin
  4299.         SavePC := pc;
  4300.         isTrue := true;
  4301.         repeat
  4302.             pc := SavePC;
  4303.             GetToken;
  4304.             while (token <> untilT) and (token <> DoneT) do begin
  4305.                     DoStatement;
  4306.                     GetToken;
  4307.                     if Token = SemiColon then
  4308.                         GetToken;
  4309.                     if CommandPeriod then
  4310.                         token := DoneT;
  4311.                 end;
  4312.             if token <> untilT then
  4313.                 MacroError(UntilExpected);
  4314.             isTrue := GetBoolean;
  4315.             if Digitizing then
  4316.                 DoCapture;
  4317.         until isTrue or (Token = DoneT);
  4318.     end;
  4319.  
  4320.  
  4321.     procedure SkipRepeat;
  4322.     begin
  4323.         GetToken;
  4324.         while (token <> untilT) and (token <> DoneT) do begin
  4325.                 SkipStatement;
  4326.                 GetToken;
  4327.                 if token = SemiColon then
  4328.                     GetToken
  4329.                 else if token <> UntilT then
  4330.                     MacroError(UntilExpected);
  4331.             end;
  4332.         GetToken;
  4333.         SkipPartialStatement;
  4334.     end;
  4335.  
  4336.  
  4337.     procedure DoArrayAssignment;
  4338.         var
  4339.             SaveCommand: CommandType;
  4340.             index, LutValue, PixelValue, RegisterValue: LongInt;
  4341.             SyncChannel: integer;
  4342.     begin
  4343.         SaveCommand := MacroCommand;
  4344.         GetToken;
  4345.         if token <> LeftBracket then
  4346.             MacroError('"[" expected');
  4347.         Index := GetInteger;
  4348.         GetToken;
  4349.         if token <> RightBracket then
  4350.             MacroError('"]" expected');
  4351.         GetToken;
  4352.         if token <> AssignOp then
  4353.             MacroError('":=" expected');
  4354.  
  4355.         if SaveCommand = BufferC then begin
  4356.                 CheckIndex(index, 0, MaxLine - 1);
  4357.                 PixelValue := GetInteger;
  4358.                 RangeCheck(PixelValue);
  4359.                 if token <> DoneT then
  4360.                     MacrosP^.aLine[index] := PixelValue;
  4361.                 exit(DoArrayAssignment);
  4362.             end;
  4363.  
  4364.         if SaveCommand in [RedLutC, BlueLutC, GreenLutC] then begin
  4365.                 CheckIndex(index, 0, 255);
  4366.                 LutValue := GetInteger;
  4367.                 RangeCheck(LutValue);
  4368.                 if token <> DoneT then
  4369.                     with info^.cTable[index].rgb do
  4370.                         case SaveCommand of
  4371.                             RedLutC: 
  4372.                                 red := bsl(LutValue, 8);
  4373.                             GreenLutC: 
  4374.                                 green := bsl(LutValue, 8);
  4375.                             BlueLutC: 
  4376.                                 blue := bsl(LutValue, 8);
  4377.                         end;
  4378.                 exit(DoArrayAssignment);
  4379.             end;
  4380.  
  4381.         if SaveCommand = ScionC then begin
  4382.                 if framegrabber <> ScionLG3 then
  4383.                     MacroError('No Scion LG-3');
  4384.                 if Token <> DoneT then
  4385.                     CheckIndex(index, 1, 4);
  4386.                 if Token = DoneT then
  4387.                     exit(DoArrayAssignment);
  4388.                 if index = 3 then
  4389.                     MacroError('DataIn is read-only');
  4390.                 RegisterValue := GetInteger;
  4391.                 if token <> DoneT then begin
  4392.                         if RegisterValue < 0 then
  4393.                             RegisterValue := 0;
  4394.                         if RegisterValue > 255 then
  4395.                             RegisterValue := 255;
  4396.                         case index of
  4397.                             1:  begin
  4398.                                     LG3DacA := RegisterValue;
  4399.                                     DacAReg^ := LG3DacA
  4400.                                 end;
  4401.                             2:  begin
  4402.                                     LG3DacB := RegisterValue;
  4403.                                     DacBReg^ := LG3DacB
  4404.                                 end;
  4405.                             4:  begin
  4406.                                     LG3DataOut := band(RegisterValue, $f);
  4407.                                     if SyncMode = SeparateSync then
  4408.                                         SyncChannel := 3
  4409.                                     else
  4410.                                         SyncChannel := VideoChannel;
  4411.                                     ChannelReg^ := bor(LG3DataOut, bor(bsl(VideoChannel, 4), bsl(SyncChannel, 6)));
  4412.                                 end;
  4413.                         end; {case}
  4414.                     end;
  4415.                 exit(DoArrayAssignment);
  4416.             end;
  4417.  
  4418.         if SaveCommand = PlotDataC then begin
  4419.                 CheckIndex(index, 0, MaxLine - 1);
  4420.                 PlotData^[index] := GetExpression;
  4421.                 exit(DoArrayAssignment);
  4422.             end;
  4423.  
  4424.         CheckIndex(index, 1, MaxMeasurements);
  4425.         if token <> DoneT then
  4426.             case SaveCommand of
  4427.                 rAreaC: 
  4428.                     mArea^[Index] := GetExpression;
  4429.                 rMeanC: 
  4430.                     mean^[Index] := GetExpression;
  4431.                 rStdDevC: 
  4432.                     sd^[Index] := GetExpression;
  4433.                 rXC: 
  4434.                     xcenter^[Index] := GetExpression;
  4435.                 rYC: 
  4436.                     ycenter^[Index] := GetExpression;
  4437.                 rLengthC: 
  4438.                     plength^[Index] := GetExpression;
  4439.                 rMinC: 
  4440.                     mMin^[Index] := GetExpression;
  4441.                 rMaxC: 
  4442.                     mMax^[Index] := GetExpression;
  4443.                 rMajorC: 
  4444.                     MajorAxis^[Index] := GetExpression;
  4445.                 rMinorC: 
  4446.                     MinorAxis^[Index] := GetExpression;
  4447.                 rAngleC: 
  4448.                     orientation^[Index] := GetExpression;
  4449.                 rUser1C: 
  4450.                     User1^[Index] := GetExpression;
  4451.                 rUser2C: 
  4452.                     User2^[Index] := GetExpression;
  4453.                 otherwise
  4454.                     MacroError('Read-only array');
  4455.             end; {case}
  4456.     end;
  4457.  
  4458.  
  4459.     procedure PushArguments (var nArgs: integer);
  4460.         var
  4461.             arg: array[1..MaxArgs] of extended;
  4462.             StringArg: array[1..MaxArgs] of boolean;
  4463.             i, nStringArgs: integer;
  4464.             TempName: SymbolType;
  4465.     begin
  4466.         nArgs := 0;
  4467.         nStringArgs := 0;
  4468.         GetToken;
  4469.         while token in [Variable, StringVariable, StringLiteral, NumericLiteral, TrueT, FalseT, FunctionT, StringFunctionT, comma, MinusOp, LeftParen] do begin
  4470.                 if token = comma then
  4471.                     GetToken;
  4472.                 if nArgs < MaxArgs then
  4473.                     nArgs := nArgs + 1
  4474.                 else
  4475.                     MacroError('Too many arguments');
  4476.                 if (token = StringVariable) or (token = StringLiteral) or (token = StringFunctionT) then begin
  4477.                         nStringArgs := nStringArgs + 1;
  4478.                         arg[nArgs] := 0.0;
  4479.                         StringArg[nArgs] := true;
  4480.                         if token = StringFunctionT then
  4481.                             TokenStr := DoStringFunction;
  4482.                     end
  4483.                 else begin
  4484.                         PutTokenBack;
  4485.                         arg[nArgs] := GetExpression;
  4486.                         StringArg[nArgs] := false;
  4487.                     end;
  4488.                 if nStringArgs > 1 then
  4489.                     MacroError('No more than one string argument allowed');
  4490.                 GetToken;
  4491.             end;
  4492.         if token <> RightParen then
  4493.             MacroError(RightParenExpected);
  4494.         for i := 1 to nArgs do begin
  4495.                 if TopOfStack < MaxStackSize then
  4496.                     TopOfStack := TopOfStack + 1
  4497.                 else
  4498.                     MacroError(StackOverflow);
  4499.                 with MacrosP^.stack[TopOfStack] do begin
  4500.                         value := arg[i];
  4501.                         StringH := nil;
  4502.                         if StringArg[i] then begin
  4503.                                 vType := StringVar;
  4504.                                 StringsAllocated := true;
  4505.                                 StringH := str255H(NewHandle(SizeOf(str255)));
  4506.                                 if StringH = nil then begin
  4507.                                         MacroError('Out of memory');
  4508.                                         Token := DoneT
  4509.                                     end
  4510.                                 else
  4511.                                     StringH^^ := TokenStr;
  4512.                             end
  4513.                         else
  4514.                             vType := RealVar;
  4515.                         value := arg[i];
  4516.                     end;
  4517.             end;
  4518.     end;
  4519.  
  4520.  
  4521.     procedure DoProcedure;
  4522.         var
  4523.             SavePC, SavePCStart, NewPCStart, SaveStackLoc, nArgs, i: integer;
  4524.             SaveProcName, NewProcName: SymbolType;
  4525.             SaveStringsAllocated: boolean;
  4526.     begin
  4527.         NewPCStart := TokenLoc;
  4528.         NewProcName := TokenSymbol;
  4529.         SaveStackLoc := TopOfStack;
  4530.         SaveStringsAllocated := StringsAllocated;
  4531.         StringsAllocated := false;
  4532.         GetToken;
  4533.         if token = LeftParen then
  4534.             PushArguments(nArgs)
  4535.         else begin
  4536.                 nArgs := 0;
  4537.                 PutTokenBack;
  4538.             end;
  4539.         SavePCStart := PCStart;
  4540.         PCStart := NewPCStart;
  4541.         LineStartPC := NewPCStart;
  4542.         SaveProcName := MacroOrProcName;
  4543.         MacroOrProcName := NewProcName;
  4544.         SavePC := pc;
  4545.         pc := pcStart;
  4546.         if nArgs > 0 then begin
  4547.                 GetLeftParen;
  4548.                 i := 0;
  4549.                 GetToken;
  4550.                 while token in [Identifier, Variable, StringVariable, comma, colon, SemiColon, RealT, IntegerT, BooleanT, StringT] do begin
  4551.                         if (token = Identifier) or (token = Variable) or (token = StringVariable) then begin
  4552.                                 if i < nArgs then
  4553.                                     i := i + 1
  4554.                                 else
  4555.                                     MacroError('Too many formal arguments');
  4556.                                 MacrosP^.stack[SaveStackLoc + i].SymbolTableIndex := SymbolTableloc;
  4557.                             end;
  4558.                         GetToken;
  4559.                     end;
  4560.                 if Token = VarT then
  4561.                     MacroError('VAR parameters not supported');
  4562.                 if i < nArgs then
  4563.                     MacroError('Too few formal arguments');
  4564.                 if token <> RightParen then
  4565.                     MacroError(RightParenExpected);
  4566.             end;
  4567.         GetToken;
  4568.         if (token = LeftParen) and (nArgs = 0) then
  4569.             MacroError('Arguments not expected');
  4570.         DoDeclarations;
  4571.         DoCompoundStatement;
  4572.         pc := SavePC;
  4573.         if StringsAllocated then
  4574.             DeallocateStrings(SaveStackLoc + 1, TopOfStack);
  4575.         StringsAllocated := SaveStringsAllocated;
  4576.         TopOfStack := SaveStackLoc;
  4577.         pcStart := SavePCStart;
  4578.         MacroOrProcName := SaveProcName;
  4579.     end;
  4580.  
  4581.  
  4582.     procedure CannotBeginWithThis;
  4583.         var
  4584.             str: str255;
  4585.     begin
  4586.         str := '';
  4587.         ConvertTokenToString(token, str);
  4588.         MacroError(concat('Statement cannot begin with ', '"', str, '"'));
  4589.     end;
  4590.  
  4591.  
  4592.     procedure DoStatement;
  4593.     begin
  4594.         case token of
  4595.             BeginT: 
  4596.                 DoCompoundStatement;
  4597.             CommandT: 
  4598.                 ExecuteCommand;
  4599.             UserCommandT: 
  4600.                 DoUserToken;
  4601.             ForT: 
  4602.                 DoFor;
  4603.             IfT: 
  4604.                 DoIf;
  4605.             WhileT: 
  4606.                 DoWhile;
  4607.             RepeatT: 
  4608.                 DoRepeat;
  4609.             Identifier: 
  4610.                 MacroError('Undefined identifier');
  4611.             Variable: 
  4612.                 DoAssignment;
  4613.             StringVariable: 
  4614.                 DoStringAssignment;
  4615.             ArrayT: 
  4616.                 DoArrayAssignment;
  4617.             ProcedureT: 
  4618.                 DoProcedure;
  4619.             ElseT: 
  4620.                 MacroError('Statement expected');
  4621.             FunctionT, StringFunctionT, UserFuncT, UserStrFuncT: 
  4622.                 MacroError('Variable expected');
  4623.             SemiColon: 
  4624.                 PutTokenBack; {Null statement}
  4625.             otherwise
  4626.                 CannotBeginWithThis
  4627.         end;
  4628.     end;
  4629.  
  4630.  
  4631.     procedure SkipStatement;
  4632.     begin
  4633.         case token of
  4634.             BeginT: 
  4635.                 SkipCompoundStatement;
  4636.             ForT: 
  4637.                 SkipFor;
  4638.             IfT: 
  4639.                 SkipIf;
  4640.             WhileT: 
  4641.                 SkipWhile;
  4642.             RepeatT: 
  4643.                 SkipRepeat;
  4644.             CommandT, Variable, ArrayT, ProcedureT: 
  4645.                 SkipPartialStatement;
  4646.             DoneT: 
  4647.                 ; {Aborting the macro}
  4648.             SemiColon, EndT, ElseT, UntilT: 
  4649.                 PutTokenBack; {These tokens can follow a statement}
  4650.             otherwise
  4651.                 CannotBeginWithThis
  4652.         end;
  4653.     end;
  4654.  
  4655.  
  4656.  
  4657.     procedure RunMacro (nMacro: integer);
  4658.         var
  4659.             count: integer;
  4660.             str: str255;
  4661.             SaveInfo: InfoPtr;
  4662.     begin
  4663.         DefaultFileName := '';
  4664.         str := '';
  4665.         nSaves := 0;
  4666.         DefaultRefNum := 0;
  4667.         count := 0;
  4668.         pcStart := MacroStart[nMacro];
  4669.         pc := pcStart;
  4670.         SavePC := pcStart;
  4671.         LineStartPC := pcStart;
  4672.         token := NullT;
  4673.         macro := true;
  4674.         MacroOpPending := false;
  4675.         DoOption := false;
  4676.         SaveInfo := info;
  4677.         TopOfStack := nGlobals;
  4678.         MacroOrProcName := BlankSymbol;
  4679.         StringsAllocated := false;
  4680.         InPhotoMode := false;
  4681.         RoutinesCalled := [];
  4682.         GetToken;
  4683.         DoDeclarations;
  4684.         DoCompoundStatement;
  4685.         if (info <> SaveInfo) and (info <> NoInfo) then
  4686.             SelectWindow(info^.wptr);
  4687.         with info^, RoiRect do begin
  4688.                 if ((right - left) <= 0) or ((bottom - top) <= 0) then
  4689.                     KillRoi;
  4690.             end;
  4691.         if info^.RoiShowing then begin
  4692.                 if MacroOpPending then begin
  4693.                         KillRoi;
  4694.                         RestoreRoi;
  4695.                     end
  4696.                 else
  4697.                     UpdatePicWindow;
  4698.             end;
  4699.         macro := false;
  4700.         if StringsAllocated then
  4701.             DeallocateStrings(nGlobals + 1, TopOfStack);
  4702.         if InPhotoMode then
  4703.             RestoreScreen;
  4704.     end;
  4705.  
  4706.  
  4707.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  4708.         const
  4709.             FunctionKey = 16;
  4710.         var
  4711.             i: integer;
  4712.     begin
  4713.         if (ord(ch) = 0) then
  4714.             exit(RunKeyMacro);
  4715.         if (ch >= 'A') and (ch <= 'Z') then
  4716.             ch := chr(ord(ch) + 32); {Convert to lower case}
  4717.         if ord(ch) = FunctionKey then
  4718.             case KeyCode of
  4719.                 122: 
  4720.                     ch := 'A';
  4721.                 120: 
  4722.                     ch := 'B';
  4723.                 99: 
  4724.                     ch := 'C';
  4725.                 118: 
  4726.                     ch := 'D';
  4727.                 96: 
  4728.                     ch := 'E';
  4729.                 97: 
  4730.                     ch := 'F';
  4731.                 98: 
  4732.                     ch := 'G';
  4733.                 100: 
  4734.                     ch := 'H';
  4735.                 101: 
  4736.                     ch := 'I';
  4737.                 109: 
  4738.                     ch := 'J';
  4739.                 103: 
  4740.                     ch := 'K';
  4741.                 111: 
  4742.                     ch := 'L';
  4743.                 105: 
  4744.                     ch := 'M';
  4745.                 107: 
  4746.                     ch := 'N';
  4747.                 113: 
  4748.                     ch := 'O';
  4749.                 otherwise
  4750.             end;
  4751.         for i := 1 to nMacros do
  4752.             if ch = MacroKey[i] then begin
  4753.                     RunMacro(i);
  4754.                     leave;
  4755.                 end;
  4756.     end;
  4757.  
  4758.  
  4759.  
  4760. end.